home *** CD-ROM | disk | FTP | other *** search
/ Mac Cube 4: Multimedia Applications / MacCube Volume 4: Multimedia Applications.iso / Graphics / POV Ray / POVSOURCE / SOURCE / Pov.c < prev    next >
Text File  |  1994-02-09  |  149KB  |  5,321 lines

  1. /*==============================================================================
  2. Project:    POV-Ray
  3.  
  4. Version:    2.2
  5.  
  6. File:    Pov.c
  7.  
  8. Description:
  9.     This file contains the main program and most other Macintosh-specific
  10.     routines for the Persistence Of Vision raytracer (POV-Ray.)
  11. ------------------------------------------------------------------------------
  12. Authors:
  13.     Thomas Okken, David Lichtman, Glenn Sugden
  14.     Jim Nitchals, David Harr, Eduard [esp] Schwan
  15. ------------------------------------------------------------------------------
  16.     from Persistence of Vision Raytracer
  17.     Copyright 1993 Persistence of Vision Team
  18. ------------------------------------------------------------------------------
  19.     NOTICE: This source code file is provided so that users may experiment
  20.     with enhancements to POV-Ray and to port the software to platforms other 
  21.     than those supported by the POV-Ray Team.  There are strict rules under
  22.     which you are permitted to use this file.  The rules are in the file
  23.     named POVLEGAL.DOC which should be distributed with this file. If 
  24.     POVLEGAL.DOC is not available or for more info please contact the POV-Ray
  25.     Team Coordinator by leaving a message in CompuServe's Graphics Developer's
  26.     Forum.  The latest version of POV-Ray may be found there as well.
  27.  
  28.     This program is based on the popular DKB raytracer version 2.12.
  29.     DKBTrace was originally written by David K. Buck.
  30.     DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
  31. ------------------------------------------------------------------------------
  32. More Info:
  33.     This Macintosh version of POV-Ray was created and compiled by Jim Nitchals
  34.     (Think 5.0) and Eduard Schwan (MPW 3.2), based (loosely) on the original
  35.     port by Thomas Okken and David Lichtman, with some help from Glenn Sugden.
  36.  
  37.     For bug reports regarding the Macintosh version, you should contact:
  38.     Eduard [esp] Schwan
  39.         CompuServe: 71513,2161
  40.         Internet: jl.tech@applelink.apple.com
  41.         AppleLink: JL.Tech
  42.     Jim Nitchals
  43.         Compuserve: 73117,3020
  44.         America Online: JIMN8
  45.         Internet: jimn8@aol.com -or- jimn8@applelink.apple.com
  46.         AppleLink: JIMN8
  47. ------------------------------------------------------------------------------
  48. Change History:
  49.     920815    [jln]    version 1.0 Mac released.
  50.     920908    [esp]    version 1.1 alpha Mac
  51.     921228    [esp]    version 1.1 beta Mac
  52.                     • Refuse to open 2nd file if 1st is rendering
  53.                     • Fix grow bounds bug on large screens
  54.                     • Single file dropped during batch render displayed error.
  55.                     • Fixed logic for various drag-n-drop cases.
  56.                     • Added dialog & code to catch non-text file drops.
  57.                     • Made GarbageCollection dialog not appear if nothing to do.
  58.                     • Fixed "auto-jump to errant line #" being off by one line.
  59.                     • Fixed bug in Open: if open failed, left New & Open items dimmed
  60.                     • Removed annoying "Finished Rendering" dialog box
  61.                     • Display true start/end time in status window for multi-renders
  62.                     • Status and Source windows have zoom boxes
  63.                     • Fixed Auto-shutdown (it wasn't)
  64.                     • Fixed Custom Palette to restore properly
  65.     930104    [esp]    1.13 sync, POVMac 1.1b19
  66.                     • Changed Splash Screen and about box to reflect the
  67.                         #defines DISTRIBUTION_MESSAGE & POV_RAY_VERSION
  68.                     • Added code in event loop to handle Disk Insert events!
  69.                     • Changed GetBestSFPos fn name to more generic GetBestDialogPos
  70.                     • Added one-liner comments above each function
  71.     930113    [esp]    1.1b20 release, looks pretty stable to me
  72.     930115  [jln]   • Fixed the good 'ol highlight bug in goto_line finally
  73.                     • Fixed bug where user entered a line # too high for goto_line
  74.                     resulted in cursor being put at the TOP of the file.
  75.                     • Fixed bug that caused Undo Typing to undo more than it
  76.                     should have (typing, cursor movement, typing counted as
  77.                     a single gCanUndo event.  Now it's two events for the typing.)
  78.                     • Fixed bug in template insertion (didn't support Undo)
  79.                     • Changed MultiFinder friendliness code (Setting 1 is now
  80.                     even friendlier; Settings 7-15 are nastier.)
  81.     930513    [esp]    1.64b20 release
  82.                     Moved some code to other C files (Animate,ImageWindow)
  83.     930614    [esp]    version 1.7b6 released
  84.     930620    [esp]    version 1.7b7 released
  85.     930709    [esp]    version 1.75b1 released
  86.     930725    [esp]    version 1.75b3 released (cancel parse bug fixed)
  87.     930903    [esp]    version 1.91b2 released (VIB bug fixed)
  88.     930911    [esp]    version 1.91b4 released (include path uses SFGetFile now)
  89.     930918    [esp]    version 1.92b1 released (AppFriendly works better, ImageWindPos restored OK)
  90.     930929    [esp]    version 1.94b2 released (removed QuickTime "No Image Comp" warning)
  91.     931001    [esp]    version 2.0 finished (Released on 10/4/93)
  92.     931005    [esp]    version 2.01b fixed cmd-O bug (every other file open fails)
  93.     931005    [esp]    version 2.01b undo & redo scroll window to where the action is
  94.     931018    [esp]    version 2.01b Changed RenderOpts AutoBound from checkbox to popup,
  95.                     display credits at startup, not 1st render, fixed include prefs logic
  96.     931119    [djh]    2.0.1 source conditionally compiles for PPC machines, keyword __powerc
  97.     940204    [esp]    2.2 prepare for release - bound slabs default OFF
  98. ==============================================================================*/
  99.  
  100.  
  101. /*==== POV-Ray std headers ====*/
  102. #include "PovMac.h"
  103. #include "povproto.h"
  104.  
  105.  
  106. /*==== Standard C headers ====*/
  107. #include <stdlib.h>
  108. #include <setjmp.h>
  109.  
  110.  
  111. /*==== Macintosh-specific headers ====*/
  112. // NOTE: _H_MacHeaders_ is defined by Think C if it is using
  113. // precompiled headers.  This is only for compilation speed improvement.
  114. #if !defined(_H_MacHeaders_)
  115. #include <Types.h>
  116. #include <Controls.h>
  117. #include <Desk.h>
  118. #include <Dialogs.h>
  119. #include <Files.h>
  120. #include <Memory.h>
  121. #include <Menus.h>
  122. #include <OSEvents.h>
  123. #include <OSUtils.h>
  124. #include <Packages.h>
  125. #include <pictutil.h>
  126. #include <QuickDraw.h>
  127. #include <Resources.h>
  128. #include <Windows.h>
  129. #include <scrap.h>
  130. #include <shutdown.h>
  131. #include <sound.h>
  132. #include <AppleEvents.h>
  133. #include <DiskInit.h>
  134. #include <GestaltEqu.h>
  135. #include <Folders.h>
  136. #include <errors.h>            /* dupFNErr, etc */
  137. #include <fonts.h>
  138. #include <segload.h>        /* UnloadSeg */
  139. #include <eppc.h>            /* kHighLevelEvent */
  140. #include <traps.h>            /* _Unimplemented */
  141. #include <string.h>            /* strcpy/cat */
  142. #include <toolutils.h>        /* BitTst, etc */
  143. #endif // _H_MacHeaders_
  144.  
  145. #if !defined (THINK_C)
  146. #include <strings.h>        /* p2cstr */
  147. #endif // THINK_C
  148.  
  149. // Debug with profiler
  150. #if defined(THINK_C) && defined(NEEDS_PROF)
  151. #include <profile.h>
  152. #endif
  153.  
  154.  
  155. /*==== POV-Ray text editor header ====*/
  156. #include "TextEditor.h"
  157.  
  158.  
  159. /*==== POV Mac Library routines =====*/
  160. #include "POVLib.h"
  161.  
  162.  
  163. /*==== Animation prompt ====*/
  164. #include "Animate.h"
  165.  
  166.  
  167. /*==== Compress PICT routines ====*/
  168. #include "SaveCmpPict.h"
  169.  
  170.  
  171. /*==== File queueing routines ====*/
  172. #include "FileQueue.h"
  173.  
  174.  
  175. /*==== Image Window routines ====*/
  176. #include "ImageWindow.h"
  177.  
  178.  
  179. /*==== Progress Bar dialog routines ====*/
  180. #include "ProgressDialog.h"
  181.  
  182.  
  183. /*==== Template submenu routines ====*/
  184. #include "TemplateMenu.h"
  185.  
  186.  
  187. /*==== General definitions ====*/
  188.  
  189. /* The Finder Events Suite - defined in the not-yet-existing <AERegistry.h> */
  190. #define kAEFinderEvents            'FNDR'
  191.  
  192. // preview picture rsrc id
  193. #define    kDemoPICTrsrcID            131
  194.  
  195. #if defined(applec)
  196. /* entry point to %a5init segment, for disposal after init */
  197. extern void _DataInit();
  198. #endif // applec
  199.  
  200.  
  201. #if defined(__powerc)
  202. // PowerPC needs its own QuickDraw global rec
  203. QDGlobals qd;
  204.  
  205. // forward declarations for routine descriptors
  206. extern pascal void DrawPopupMenu(WindowPtr dlgWindPtr, short dinum);
  207. pascal void dim_dlg_edit_text(WindowPtr dlgWindPtr, short dinum);
  208. pascal void showProgress_UProc(WindowPtr dlgWindPtr, short dinum);
  209. pascal OSErr HandleAEOapp(AEDescList *aevt, AEDescList *reply, long refCon);
  210. pascal OSErr HandleAEOdoc(AEDescList *aevt, AEDescList *reply, long refCon);
  211. pascal OSErr HandleAEQuit(AEDescList *aevt, AEDescList *reply, long refCon);
  212. pascal void MyPutPicProc( char *dataPtr, short byteCount);
  213. pascal void p2wi_VScrollActionProc(ControlHandle control, short part);
  214. pascal void p2wi_HScrollActionProc(ControlHandle control, short part);
  215. pascal void ScrollProc(ControlHandle theControl, short theCode);
  216. #endif // __powerc
  217.  
  218.  
  219. /*==== Global variables (external scope) ====*/
  220.  
  221. p2w_WindowPtr_t    gp2wWindow = NULL;            // the Status (text) window
  222.  
  223. Boolean                gHasSys70 = false;            // Can we do System 7 stuff?
  224. Boolean                gHasFSSpecs = false;         // Can use FSSpec calls?
  225. Boolean                gHasAppleEvents = false;    // Apple Events available for doing shutdown?
  226. Boolean                gHas32BitQD = false;         // is 32 bit Quickdraw available for depth & dithering
  227. Boolean                gHasPictUtils = false;        // is Picture Utils (extract best palette) avail?
  228. Boolean                gHasQuickTime = false;         // Is QuickTime available?
  229. Boolean                gHasImageCompressionMgr = false; // Is image compression available?
  230. Boolean                gHasPopups = false;            // are popup menus avail?
  231. long                gQTVersion;                    // QuicktTime version from Gestalt
  232.  
  233. Boolean                gInBackground = false;        // is the program currently switched out
  234. Boolean                gDoingRender;                // for determining the menu states
  235. Cursor                gEditCursor;
  236. Cursor                gWaitCursor;
  237. Rect                gDragBounds;                // window dragging boundary
  238.  
  239. app_prefs_hdl_t        gAppPrefs_h = NULL;            // App prefs from prefs file
  240. file_prefs_hdl_t    gFilePrefs_h = NULL;        // each file has its own prefs
  241. file_prefs_hdl_t    gDefltFilePrefs_h = NULL;    // default file prefs from prefs file
  242. file_prefs_hdl_t    gPrefs2Use_h = NULL;        // points to file or default prefs
  243.  
  244. Boolean                gCanUndo = false;            // can we undo this operation?
  245.  
  246. /*==== Global variables (local scope) ====*/
  247.  
  248. static Boolean        gAutoShutdown = false;        // flag for auto-shutdown on completion
  249. static Boolean        gAutoSave = false;            // flag for auto-save image on completion
  250. static Boolean        gBeginRendering = false;    // True when user pick Render from menu
  251. static Boolean        gUseAppDefaultPrefs = false; // True if overriding file prefs
  252.  
  253. // Animation-related
  254. static Boolean        gInAnimationLoop = false;    // True when rendering an animation file
  255. static AnimRec_t    gAnimRec;                    // current animation frame/clock info
  256.  
  257. // argv/argc variables for passing to POV-Ray engine
  258. #define    ARGV_Size    64
  259. #define    ARGSTR_Size    1024
  260.  
  261. static int            ARGC;
  262. static char            **ARGV, *argstr, *argptr;
  263.  
  264.  
  265. static StringPtr    gDistMessage;                // concatenated from FRAME.H strings
  266. static jmp_buf        gSetJmpEnv;                    // exit state
  267.  
  268. // resource file reference numbers
  269. static short        AppRefNum = kRsrcFileClosed,
  270.                     AppPrefsRefNum = kRsrcFileClosed,
  271.                     SrcResRefNum = kRsrcFileClosed;
  272.  
  273. static char            gTargaFname[64];            // name of Targa output file
  274.  
  275. static Boolean        gDoingBatchODOCs = false;     // in the middle of ODOC, postpone other odocs
  276.  
  277. static long            gPrevTickCount;                // Time of last WNE time slice
  278. static long            gCpuHogginess;                // how long to stay here before relinquishing
  279. static long            gWNEReleaseTicks;            // how long to yield to other apps
  280.  
  281. static MenuHandle    myMenus[num_of_menus];
  282. static MenuHandle    mySubMenus[num_of_submenus];
  283. static EventRecord    gTheEvent;
  284.  
  285. static Boolean        gQuit = false;
  286. static short        gPaused = 0;
  287.  
  288. static DialogPtr    gSplashScreen = NULL;
  289. static long            gSplashStartTicks = 0;
  290.  
  291. static short        gRenderedOK = false;
  292. static long            TargetTicks;
  293.  
  294.  
  295. // This array mirrors the "Preset Image Sizes" popup menu (#302)
  296. // I could GetItem & parse the numbers out of the menu, more versatile...
  297. #define SCRN_SIZE_MENU_MAX    19
  298. #define kDfltScrnSize        5        // default screen size
  299. static short    scrnSizeMenu[SCRN_SIZE_MENU_MAX][2] =
  300. {
  301. //    x/w        y/h
  302.     8,        8,        // [0]
  303.     16,        16,        // [1]
  304.     32,        32,        // [2]
  305.     64,        64,        // [3]
  306.     80,        80,        // [4]
  307.     100,    100,    // [5]
  308.     128,    128,    // :::
  309.     160,    120,
  310.     320,    200,
  311.     320,    240,
  312.     512,    342,
  313.     512,    384,
  314.     640,    400,
  315.     640,    480,
  316.     640,    870,
  317.     832,    624,
  318.     1152,    870,
  319.     1024,    1024,
  320.     2048,    2048    // [SCRN_SIZE_MENU_MAX-1]
  321. };
  322.  
  323. #if defined(__powerc)
  324. // routine descriptor globals
  325. RoutineDescriptor gModalFilterRD = BUILD_ROUTINE_DESCRIPTOR(uppModalFilterProcInfo, ModalFilter);
  326. RoutineDescriptor gOutlineButtonRD = BUILD_ROUTINE_DESCRIPTOR(uppUserItemProcInfo, outlineDefaultButton);
  327. RoutineDescriptor gPopupMenuRD = BUILD_ROUTINE_DESCRIPTOR(uppUserItemProcInfo, DrawPopupMenu);
  328. RoutineDescriptor gDimDlogTextRD = BUILD_ROUTINE_DESCRIPTOR(uppUserItemProcInfo, dim_dlg_edit_text);
  329. RoutineDescriptor gShowProgressRD = BUILD_ROUTINE_DESCRIPTOR(uppUserItemProcInfo, showProgress_UProc);
  330. RoutineDescriptor gAEOAppRD = BUILD_ROUTINE_DESCRIPTOR(uppEventHandlerProcInfo, HandleAEOapp);
  331. RoutineDescriptor gAEODocRD = BUILD_ROUTINE_DESCRIPTOR(uppEventHandlerProcInfo, HandleAEOdoc);
  332. RoutineDescriptor gAEQuitRD = BUILD_ROUTINE_DESCRIPTOR(uppEventHandlerProcInfo, HandleAEQuit);
  333. RoutineDescriptor gVScrollRD = BUILD_ROUTINE_DESCRIPTOR(uppControlActionProcInfo, p2wi_VScrollActionProc);
  334. RoutineDescriptor gHScrollRD = BUILD_ROUTINE_DESCRIPTOR(uppControlActionProcInfo, p2wi_HScrollActionProc);
  335. RoutineDescriptor gScrollRD = BUILD_ROUTINE_DESCRIPTOR(uppControlActionProcInfo, ScrollProc);
  336. RoutineDescriptor gPutPICTRD = BUILD_ROUTINE_DESCRIPTOR(uppQDPutPicProcInfo, MyPutPicProc);
  337. #endif // __powerc
  338.  
  339.  
  340. /*==== QuickTime globals ====*/
  341.  
  342. static ComponentInstance    gtheSCComponent = NULL;    
  343.  
  344.  
  345. /*==== text editor undo globals ====*/
  346.  
  347. #define        max_undo         16
  348.  
  349. typedef struct
  350. {
  351.     char            *buffer;
  352.     char            **buf_handle;
  353.     short            isDirty;
  354.     long            byteCount;
  355.     long            selStart;
  356.     long            selEnd;
  357.     char            reason[16];
  358. } undoStruct;
  359.  
  360. static int                undoCount;
  361. static char                undo_menu_name[32];
  362. static char                redo_menu_name[32];
  363. static int                undo_key_copied;
  364. static undoStruct        undo_record[max_undo+1];
  365. static undoStruct        redo_record[max_undo+1];
  366.  
  367.  
  368.  
  369. // ---------------------------------------------------------------------
  370. // This is a user item proc for drawing default dialog button outlines
  371. pascal void outlineDefaultButton(DialogPtr theDialog, short theItem)
  372. {
  373. #pragma unused (theItem)
  374.     PenState    SavePen;
  375.     short        itemType;
  376.     Handle        itemHandle;
  377.     Rect        dispRect;
  378.  
  379.     GetPenState(&SavePen);
  380.  
  381.     /* use 'ok' (#1) item's rectangle */
  382.     GetDItem(theDialog, ok, &itemType, &itemHandle, &dispRect);
  383.     SetPort(theDialog);
  384.  
  385.     PenSize(3, 3);
  386.     InsetRect(&dispRect, -4, -4);
  387.     FrameRoundRect(&dispRect, 16, 16);
  388.  
  389.     SetPenState(&SavePen);
  390. } // outlineDefaultButton
  391.  
  392.  
  393. // ---------------------------------------------------------------------
  394. // Sets dialog #3 item's display proc to draw outline around item #1
  395. void SetupDefaultButton(DialogPtr theDialog)
  396. {
  397.     short    itemtype;
  398.     Rect    itemrect;
  399.     Handle    tempHandle;
  400.  
  401.     /* Set up User item (always #3) to display a border around OK button (#1) */
  402.     GetDItem(theDialog, kDefaultItem, &itemtype, &tempHandle, &itemrect);
  403. #if defined(__powerc)
  404.     SetDItem(theDialog, kDefaultItem, itemtype, (Handle)&gOutlineButtonRD, &itemrect);
  405. #else
  406.     SetDItem(theDialog, kDefaultItem, itemtype, (Handle)&outlineDefaultButton, &itemrect);
  407. #endif // __powerc
  408. } // SetupDefaultButton
  409.  
  410.  
  411. // ---------------------------------------------------------------------
  412. // returns the ControlHandle for the item in the dialog box
  413. ControlHandle GrabDItemHandle(DialogPtr theDialog, short theGetItem)
  414. {
  415.     short    itemtype;
  416.     Rect    itemrect;
  417.     Handle    tempHandle;
  418.     
  419.     GetDItem(theDialog, theGetItem, &itemtype, &tempHandle, &itemrect);
  420.     return((ControlHandle)tempHandle);
  421. } // GrabDItemHandle
  422.  
  423.  
  424. // ---------------------------------------------------------------------
  425. // ModalFilterProc - handles mapping the Return/Enter/Esc keys, and the
  426. // special case of accepting Return if in certain EditText dialog fields
  427. pascal Boolean ModalFilter(DialogPtr theDialog, EventRecord *theDialogEvent, short *theDialogItem)
  428. {
  429.     WindowPtr    tempGP;
  430.     char        theKey;
  431.     long        tilticks;
  432.     Boolean        returnVal = false; // not yet handled
  433.  
  434.     /* remember where we parked */
  435.     GetPort(&tempGP);
  436.     SetPort(theDialog);
  437.  
  438.     /* Deal with KeyDowns */
  439.     if ((theDialogEvent->what == keyDown) || (theDialogEvent->what == autoKey))
  440.     {
  441.         theKey = theDialogEvent->message & charCodeMask;
  442.  
  443.         /* Do filtering for <ESC> and <CR> as OK and Cancel, per Human Interface guidelines. */
  444.         switch (theKey)
  445.         {
  446.             /* Make the Enter key identical to the Return key! */
  447.             case kEnterKey:
  448.                 /* Mask out the Enter key, and OR in the Return key */
  449.                 theDialogEvent->message = (theDialogEvent->message & ~charCodeMask) | kReturnKey;
  450.                 /* now drop through and handle what the Return key would do */
  451.             
  452.             /* This filters for Return or Enter as item 1, and Esc as item 2 */
  453.             case kReturnKey:
  454.                 *theDialogItem = ok;            /* change whatever the current item is to the OK item */
  455.                 /* now we need to invert the button */
  456.                 HiliteControl(GrabDItemHandle(theDialog, ok), inButton);
  457.                 Delay(8, &tilticks);            /* wait about 8 ticks so they can see it */
  458.                 HiliteControl(GrabDItemHandle(theDialog, ok), false);
  459.                 returnVal = true;
  460.                 break;
  461.             
  462.             /* This filters the escape key the same as item 2 (the canx button, usually ) */
  463.             case kEscKey:
  464.                 *theDialogItem = cancel;        /* pretend the cancel button was hit */
  465.                 HiliteControl(GrabDItemHandle(theDialog, cancel), inButton);
  466.                 Delay(8, &tilticks);            /* wait about 8 ticks so they can see it */
  467.                 HiliteControl(GrabDItemHandle(theDialog, cancel), false);
  468.                 returnVal = true;
  469.                 break;
  470.         } // switch
  471.     } // if keydown
  472.     else
  473.     {    // handle popup menus if some installed in dialog
  474.         if ((theDialogEvent->what == mouseDown) && PopupsExist())
  475.             PopupMouseDnDlgFilterProc(theDialog, theDialogEvent, theDialogItem);
  476.     }
  477.  
  478.     SetPort(tempGP);
  479.  
  480.     return(returnVal);
  481.  
  482. } // ModalFilter
  483.  
  484.  
  485. // ---------------------------------------------------------------------
  486. // Displays a dialog. param ^0 is the error #, ^1 is the string
  487. short displayDialog(short dlogID,
  488.                     char * s, short err,
  489.                     WindCentering_t doCentering,
  490.                     WindPositioning_t whereToShow)
  491. {
  492.     short        itemHit = 0;
  493.     DialogPtr    myDialog;
  494.     char        numstr[10];
  495.  
  496.     // make sure we're looking down the right resource chain
  497.     UseResFile(AppRefNum);
  498.  
  499.     (void)CompactMem(FreeMem());    // force a purge, get some memory
  500.  
  501.     SetCursor(&qd.arrow); // it could still be an I-beam or watch!
  502.  
  503.     // get the dialog
  504.     myDialog = GetNewDialog(dlogID, (Ptr)0L, (WindowPtr)-1L);
  505.  
  506.     if (!myDialog)
  507.         SysBeep(2); // can't get dialog, at least beep
  508.     else
  509.     {
  510.         // convert error string to P-style if not null
  511.         if (s != NULL)
  512.             c2pstr(s);
  513.  
  514.         // see if there is an error number
  515.         numstr[0] = '\0';
  516.         if (err != 0)
  517.             NumToString(err, (StringPtr)numstr);
  518.  
  519.         // stick parms into dialog
  520.         ParamText((StringPtr)numstr, (StringPtr)s, "\p", "\p");
  521.  
  522.         // put it where it should be
  523.         PositionWindow(myDialog, doCentering, whereToShow, (WindowPtr)gp2wWindow);
  524.         // "default" the OK button
  525.         SetupDefaultButton(myDialog);
  526.         // show it
  527.         ShowWindow(myDialog);
  528.         // prompt the user
  529. #if defined(__powerc)
  530.         ModalDialog((ModalFilterUPP)&gModalFilterRD, &itemHit);
  531. #else
  532.         ModalDialog(ModalFilter, &itemHit);
  533. #endif // __powerc
  534.         // all done with it
  535.         DisposeDialog(myDialog);
  536.     }
  537.  
  538.     return itemHit;
  539.  
  540. } // displayDialog
  541.  
  542.  
  543. // ---------------------------------------------------------------------
  544. // Find the best x,y point for a dialog, by finding which screen
  545. // the status window is on and offsetting from there.  Used by
  546. // dialog routines like SFGetFile and DIBadMount.
  547. void GetBestDialogPos(Point * wherep)
  548. {
  549.     Rect        sfRect;
  550.     GDHandle    thGDev;
  551.  
  552.     // find rect of screen that status window is on..
  553.     GetGlobalWindowRect((WindowPtr)gp2wWindow, &sfRect);
  554.     thGDev = GetClosestGDevice(&sfRect);
  555.     sfRect = (**thGDev).gdRect;
  556.  
  557.     // ..and offset SF Dialog on that screen
  558.     wherep->h = sfRect.left + 40;
  559.     wherep->v = sfRect.top + 80;
  560. } // GetBestDialogPos
  561.  
  562.  
  563. // ---------------------------------------------------------------------
  564. // Dispose and recreate an empty file list queue
  565. static void HaltFileQ()
  566. {
  567.     // halt any multi-doc processes
  568.     gDoingBatchODOCs = false;
  569.  
  570.     FileQ_d();    // Tear down ODOC File Queue
  571.     FileQ_c();  // re-create it, empty
  572. } // HaltFileQ
  573.  
  574.  
  575. // ---------------------------------------------------------------------
  576. /*------- coming soon.. when we get an FSSpec-friendly Editor
  577. // System 6 AND System 7 compatible routine to create an FSSpec
  578. static OSErr MyMakeFSSpec(short pVRefNum, long pDirID, StringPtr pFname, FSSpecPtr pTheFSFilePtr)
  579. {
  580.     OSErr    anError = noErr;
  581.     if (gSystem7OrBetter)
  582.         anError = FSMakeFSSpec(pVRefNum, pDirID, pFname, pTheFSFilePtr);
  583.     else
  584.     {    // fake it!
  585.         pTheFSFilePtr->vRefNum = pVRefNum;
  586.         pTheFSFilePtr->parID = pDirID;
  587.         BlockMove(pFname, pTheFSFilePtr->name, 1+pFname[0]);
  588.     }
  589.     return anError;
  590. } // MyMakeFSSpec
  591. -----------*/
  592.  
  593.  
  594. // ---------------------------------------------------------------------
  595. // Send a System Seven Shutdown AppleEvent to the Finder to shut us all down
  596. static void SendAEShutdown(void)
  597. {
  598.     OSErr        myErr;
  599.     OSType        theSignature;
  600.     AppleEvent    myAEvt, myReturnEvt;
  601.     AEAddressDesc    myServerAddress;
  602.  
  603.     theSignature = 'MACS'; // Finder signature.. of course!?
  604.     myErr = AECreateDesc(typeApplSignature, (Ptr)&theSignature, 4, &myServerAddress);
  605.     if (!myErr)
  606.         myErr = AECreateAppleEvent(kAEFinderEvents,            // Event Class
  607.                                     kAEShutDown,            // Event ID
  608.                                     &myServerAddress,        // Target Adr
  609.                                     kAutoGenerateReturnID,    // Return aevt ID
  610.                                     kAnyTransactionID,        // Trans ID
  611.                                     &myAEvt);                // fill me in
  612.     if (!myErr)
  613.         myErr = AESend(&myAEvt,
  614.                         &myReturnEvt,
  615.                         kAENoReply,                // send mode
  616.                         kAENormalPriority,        // send priority
  617.                         kNoTimeOut,                // N timeout ticks
  618.                         NULL,                    // idleProcPtr
  619.                         NULL);                    // EventFilterProcPtr
  620.     /* may as well clean up before we die :-) */
  621.     if (!myErr)
  622.         myErr = AEDisposeDesc(&myServerAddress);
  623. } // SendAEShutdown
  624.  
  625.  
  626.  
  627. // ---------------------------------------------------------------------
  628. // Returns the short version string in the application's version resource
  629. static void GetAppVersionPString(short versID, Str31 versionString)
  630. {
  631.     VersRecHndl    versHandle;        // VersRecHndl declared in MPW's <files.h>
  632.     
  633.     /* Get the resource string from app, 'vers' versID (1 or 2) resource! */
  634.     versHandle = (VersRecHndl)GetResource('vers',versID);
  635.     if (versHandle)
  636.     {
  637.         HLock((Handle)versHandle);
  638.         BlockMove((**versHandle).shortVersion, versionString, (**versHandle).shortVersion[0]+1);
  639.         ReleaseResource((Handle)versHandle);
  640.     }
  641.     else
  642.         versionString[0] = 0;
  643. } // GetAppVersionPString
  644.  
  645.  
  646.  
  647. // ---------------------------------------------------------------------
  648. // Calculate MultiFinder yield time as a function of hogginess.
  649. // If the user is making POV-Ray extra friendly, yield more background
  650. // ticks.  If user's making us extra hoggy, yield no background ticks.
  651. //  gCPUHogginess  gWNEReleaseTicks
  652. //     1                32
  653. //     2                24
  654. //     3                24
  655. //     4                16
  656. //     5                16
  657. //     6                 8
  658. //     7                 8
  659. //     8                 4
  660. //     9                 4
  661. //    10                 0
  662. //    11                 0
  663. static void CalcCpuReleaseTicks(Boolean AllowVerbose)
  664. {
  665.     // # of ticks to release control to other apps
  666.     gWNEReleaseTicks = ((kMaxMultiFriendly - gCpuHogginess)>>1)<<2;
  667.     if ( AllowVerbose && ((**gPrefs2Use_h).progress >= kProgDebug) )
  668.         printf("-d AppPriority=%ld, ReleaseTimes=%ld\n", gCpuHogginess, gWNEReleaseTicks);
  669. }
  670.         
  671.  
  672. // ---------------------------------------------------------------------
  673. // Convert current date/time into an ASCII C string for display
  674. static char * GetDateTimeString(char *pbuff)
  675. {
  676.     unsigned long    dtsecs;
  677.     char            tbuff[64];
  678.     
  679.     // Does anybody really know what time it is?
  680.     GetDateTime(&dtsecs);
  681.  
  682.     // convert date to string
  683.     IUDateString(dtsecs, shortDate, (StringPtr)tbuff);
  684.     p2cstr((StringPtr)tbuff);
  685.     strcpy(pbuff, tbuff);
  686.  
  687.     // put date/time separator in buffer
  688.     strcat(pbuff, "  ");
  689.  
  690.     // convert time to string
  691.     IUTimeString(dtsecs, true, (StringPtr)tbuff);
  692.     p2cstr((StringPtr)tbuff);
  693.     strcat(pbuff, tbuff);
  694.  
  695.     // "give user his filled buffer back"
  696.     return (pbuff);
  697. } // GetDateTimeString
  698.  
  699.  
  700. // ---------------------------------------------------------------------
  701. // Force all menus to be disabled
  702. static void DisableMenus(void)
  703. {
  704.     int i;
  705.  
  706.     for (i = 1; i < num_of_menus; i++)
  707.         DisableItem(myMenus[i], 0);
  708.  
  709.     // if System 6, disable about too.  Don't do this under 7.0,
  710.     // otherwise OS turns OFF ALL MENUS, including help, app, & script menus!
  711.     if (gHasSys70)
  712.     {
  713.         EnableItem(myMenus[apmn_ID - menu_offset], apmn_about);
  714.     }
  715.     else
  716.         DisableItem(myMenus[apmn_ID - menu_offset], apmn_about);
  717.  
  718.     HiliteMenu(0);
  719.     DrawMenuBar();
  720. } // DisableMenus
  721.  
  722.  
  723. // ---------------------------------------------------------------------
  724. // Force all menus to be enabled
  725. static void EnableMenus(void)
  726. {
  727.     int i;
  728.     for (i = 1; i < num_of_menus; i++)
  729.         EnableItem(myMenus[i], 0);
  730.  
  731.     // If under System 6, re-enable the about item, see above DisableMenus
  732.     if (!gHasSys70)
  733.     {
  734.         EnableItem(myMenus[apmn_ID - menu_offset], apmn_about);
  735.     }
  736.  
  737.     HiliteMenu(0);
  738.     DrawMenuBar();
  739. } // EnableMenus
  740.  
  741.  
  742. // ---------------------------------------------------------------------
  743. // Shut down the Mac power (System 6 or 7)
  744. static void DoShutdownMac()
  745. {
  746.     if (gHasAppleEvents)
  747.         SendAEShutdown();
  748.     else
  749.         ShutDwnPower(); // System 6 call
  750. } // DoShutdownMac
  751.  
  752.  
  753. // ---------------------------------------------------------------------
  754. // Play Jim's nifty sound
  755. static void PlayNotifySound(void)
  756. {
  757.     Handle the_snd_handle;
  758.     OSErr myErr;
  759.  
  760.     the_snd_handle = GetNamedResource('snd ',"\pFileDone");
  761.     if (the_snd_handle)
  762.         myErr = SndPlay(NULL, the_snd_handle, TRUE);
  763. } // PlayNotifySound
  764.  
  765.  
  766. // ---------------------------------------------------------------------
  767. // Show an ALL DONE dialog
  768. static void ShowNotifyDialog(void)
  769. {
  770.     if (!gRenderedOK) // ray tracing error
  771.         (void)displayDialog(143, NULL, 0, ewcDoCentering, eSameAsPassedWindow);
  772.     else    // completed OK
  773.         (void)displayDialog(142, NULL, 0, ewcDoCentering, eSameAsPassedWindow);
  774. } // ShowNotifyDialog
  775.  
  776.  
  777. // ---------------------------------------------------------------------
  778. // Clean up malloc residue, show progress bar too
  779. static void Collect_Garbage(void)
  780. {
  781.     DialogPtr    progressDialogPtr = NULL;
  782.  
  783.     // Do we need to do anything?
  784.     if (POV_need_to_reclaim())
  785.         {
  786.         DisableMenus();
  787.         SetCursor(&gWaitCursor);
  788.  
  789.         // create the please wait dialog
  790.         progressDialogPtr = GetNewProgressDialog(151, 3); // dlog ID, progress item ID
  791.         if (progressDialogPtr)
  792.         {
  793.             PositionWindow(progressDialogPtr, ewcDoCentering, eSameAsPassedWindow, (WindowPtr)gp2wWindow);
  794.             ShowWindow(progressDialogPtr);
  795.             SelectWindow(progressDialogPtr);
  796.             DrawDialog(progressDialogPtr);
  797.             TargetTicks = TICKS + 1*60; // stay up at least 1 second
  798.             // make sure dialog is drawn
  799.             Cooperate(true);
  800.         }
  801.  
  802.         // do the reclamation
  803.         POV_reclaim((**gPrefs2Use_h).progress >= kProgMinimal, progressDialogPtr);
  804.  
  805.         // tear down the dialog box when done
  806.         if (progressDialogPtr)
  807.         {
  808.             // Avoid any temporary flashes, make sure it's up for a
  809.             // little bit of time, no matter what..
  810.             while (TICKS < TargetTicks)
  811.                 {
  812.                 };
  813.             disposeProgressDialog(progressDialogPtr);
  814.         }
  815.  
  816.         // restore menus and cursor
  817.         EnableMenus();
  818.         SetCursor(&qd.arrow);
  819.     }
  820. } // Collect_Garbage
  821.  
  822.  
  823. // ---------------------------------------------------------------------
  824. // Change the type/creator of the Targa output file
  825. static void ChangeTargaType(void)
  826. {
  827.     OSErr i;
  828.     FInfo myFileInfo;
  829.  
  830.     c2pstr(gTargaFname);
  831.  
  832.     // Get file info, so we can change it
  833.     i = GetFInfo ((StringPtr)gTargaFname, gSrcWind_VRefNum, &myFileInfo);
  834.     if (i==0)
  835.     {
  836.         myFileInfo.fdType = 'TPIC';
  837.         myFileInfo.fdCreator = (**gPrefs2Use_h).targaFileCreator;
  838.         i = SetFInfo ((StringPtr)gTargaFname, gSrcWind_VRefNum, &myFileInfo);
  839.     }
  840.     p2cstr((StringPtr)gTargaFname);
  841. } // ChangeTargaType
  842.  
  843.  
  844.  
  845. // ---------------------------------------------------------------------
  846. // Set up to call the renderer, call it, and clean up after it returns
  847. static void call_main(int argc, char **argv)
  848. {
  849.     char    timeBuffer[128];
  850.  
  851.     dispose_virtual(); /* Disposes all old Pixmaps & deletes virtual file */
  852.  
  853.     gPrevTickCount = TICKS;
  854.     gRenderedOK = true;    /* presume that rendering will finish OK */
  855.  
  856.     // clean up any old parse memory from previous run
  857.     Collect_Garbage();    
  858.  
  859.     Max_Trace_Level = 5.0; // render.c
  860.     token_count = 0; // tokenize.c
  861.     line_count = 10; // tokenize.c
  862.  
  863.     p2cstr(gSrcWind_FileName);
  864.     printf("-- [Start]  File=%s,  Time=%s\n", gSrcWind_FileName, GetDateTimeString(timeBuffer));
  865.     c2pstr((char*)gSrcWind_FileName);
  866.  
  867.     // Track our memory inside POV core code
  868.     POV_enable_memtracking(true);
  869.  
  870.     // Return here if 'exit()' called
  871.     if (setjmp(gSetJmpEnv) == 0)
  872.     {
  873. #if defined(THINK_C) && defined(NEEDS_PROF)
  874.         // Turn on Think C's profiler
  875.         // InitProfile(maxSyms,maxCallDepth)
  876.         InitProfile(300,300);
  877.         freopen("POV.ProfileRpt","w",stdout);
  878.         _profile = 1;
  879. //        _trace = 1;
  880. #endif
  881.         alt_main(argc, argv);
  882.  
  883. #if defined(THINK_C) && defined(NEEDS_PROF)
  884.         _profile = 0;
  885.         _trace = 0;
  886.         // Dump Think C's profiler report
  887.         DumpProfile();
  888.         fclose(stdout);
  889.         gQuit = true; // no reason to stick around.
  890. #endif
  891.     }
  892.  
  893.     // all done tracking, turn it off
  894.     POV_enable_memtracking(false);
  895.  
  896.     if (gRenderedOK && (**gPrefs2Use_h).createTargaOutfile)
  897.         ChangeTargaType();    /* change type and creator of the Targa output file */
  898.     InvalRect_ImageWindow(true);
  899.  
  900.     p2cstr(gSrcWind_FileName);
  901.     printf("-- [Finish]  File=%s,  Time=%s\n", gSrcWind_FileName, GetDateTimeString(timeBuffer));
  902.     c2pstr((char*)gSrcWind_FileName);
  903.  
  904.     gDoingRender = false;
  905. } // call_main
  906.  
  907.  
  908. // ---------------------------------------------------------------------
  909. // Allocate memory for the fake argv parameter buffer
  910. static void InitArgs(void)
  911. {
  912.     ARGV = (char**)malloc(ARGV_Size*sizeof(char*));
  913.     argstr = (char*)malloc(ARGSTR_Size);
  914.     argptr = NULL;
  915.     ARGC = 0;
  916. } // InitArgs
  917.  
  918.  
  919. // ---------------------------------------------------------------------
  920. // Reset argv/argc to begin adding args
  921. static void ResetArgs(void)
  922. {
  923.     ARGC = 0;
  924.     argptr = argstr;
  925. }
  926.  
  927.  
  928. // ---------------------------------------------------------------------
  929. // Add "s" as the next parameter in the argv/argc list
  930. static void AddArg(const char *s)
  931. {
  932.     if ((**gPrefs2Use_h).progress >= kProgDebug)
  933.         printf("-d argv='%s', argc=%d, argcMax=%d\n",
  934.                 s, (int)(argptr-argstr), ARGSTR_Size);
  935.  
  936.     if ((argptr-argstr)+strlen(s) < ARGSTR_Size)
  937.     {
  938.         ARGV[ARGC++] = argptr;
  939.         while (*argptr++ = *s++)
  940.             ;
  941.     }
  942.     else
  943.     {
  944.         printf("## [Error!] Argument overflow adding '%s'!  index=%d, max=%d\n",
  945.                 s, (int)(argptr-argstr), ARGSTR_Size);
  946.     }
  947. } // AddArg
  948.  
  949.  
  950. // ---------------------------------------------------------------------
  951. // Pin the value x between a and b, i.e.  a <= x <= b
  952. static void PinValue(short *x, short a, short b)
  953. {
  954.     if (*x < a)
  955.         *x = a;
  956.     else
  957.         if (*x > b)
  958.             *x = b;
  959. } // PinValue
  960.  
  961.  
  962. // ---------------------------------------------------------------------
  963. // Move the source window's selection to the line # passed
  964. static void goto_line(short line_to_go)
  965. {
  966.     short        i;
  967.     short        line_counter = 1,
  968.                 mySelStart = -1,
  969.                 mySelEnd = -1;
  970.     Boolean        foundStart = false;
  971.     short        theMaxLength = (**gSrcWind_TEH).teLength-1;
  972.     char        *myptr = *(**gSrcWind_TEH).hText;
  973.  
  974.     /* (Line 1 is a special case, of course!) */
  975.     if (line_to_go <= 1)
  976.     {
  977.         mySelStart = 0;
  978.         foundStart = true;
  979.     }
  980.  
  981.     /* Find start and end of line */
  982.     for (i = 0; i < theMaxLength; i++)
  983.         if (myptr[i] == 0x0d)
  984.             if (!foundStart)
  985.             {    /* still looking for start of the line */
  986.                 line_counter += 1;
  987.                 if (line_counter == line_to_go)
  988.                 {
  989.                     mySelStart = i + 1;
  990.                     foundStart = true;
  991.                 }
  992.             }
  993.             else
  994.             {    /* now we found the end of the line */
  995.                 mySelEnd = i + 1;
  996.                 break;
  997.             }
  998.  
  999.     /* Beep if we found no start of line */
  1000.     if ((mySelStart < 0) && (line_to_go > 1))
  1001.     {    /* Hmm, didn't find it! */
  1002.         mySelStart = theMaxLength;
  1003.         mySelEnd = theMaxLength;
  1004.         SysBeep(4);
  1005.     }
  1006.  
  1007.     /* if no end of line found, ASSUME it is last line of file  */
  1008.     if (mySelEnd < mySelStart)
  1009.         mySelEnd = theMaxLength;
  1010.  
  1011.     /* Set up TE with selection */
  1012.     (**gSrcWind_TEH).selStart = mySelStart;
  1013.     (**gSrcWind_TEH).selEnd = mySelEnd;
  1014.  
  1015.     /* show them that we're not in Kansas anymore! */
  1016.     SelectWindow(gSrcWind_Window);
  1017.     SetPort(gSrcWind_Window);
  1018.     InvalRect(&(gSrcWind_Window->portRect));
  1019.     ShowSelect();
  1020. } // goto_line
  1021.  
  1022.  
  1023.  
  1024. #define    kItem_LineNum    4
  1025.  
  1026. // ---------------------------------------------------------------------
  1027. // prompt for which line # to go to, and go to it
  1028. static void choose_goto_line(void)
  1029. {
  1030.     short        i, dummyInt, line_to_go;
  1031.     short        itemHit;
  1032.     DialogPtr    myDialog;
  1033.     Rect        displayRect;
  1034.     ControlHandle cntl[kItem_LineNum+1];
  1035.     char        s1[128];
  1036.  
  1037.     DisableMenus();
  1038.     
  1039.     line_to_go = 1; /* for now */
  1040.     myDialog = GetNewDialog(150, NULL, (WindowPtr) -1);
  1041.     for (i = 1; i <= kItem_LineNum; i++)
  1042.         GetDItem(myDialog, i, &dummyInt, (Handle *) &cntl[i], &displayRect);
  1043.     sprintf(s1, "%d", line_to_go); 
  1044.     SetIText((Handle) cntl[kItem_LineNum], c2pstr(s1) );
  1045.     SelIText(myDialog, kItem_LineNum, 0, 32767);
  1046.     PositionWindow(myDialog, ewcDoCentering, eSameAsPassedWindow, (WindowPtr)gp2wWindow);
  1047.     /* "default" the OK button */
  1048.     SetupDefaultButton(myDialog);
  1049.     ShowWindow(myDialog);
  1050.     do
  1051.     {
  1052. #if defined(__powerc)
  1053.         ModalDialog((ModalFilterUPP)&gModalFilterRD, &itemHit);
  1054. #else
  1055.         ModalDialog((ModalFilterProcPtr)ModalFilter, &itemHit);
  1056. #endif // __powerc
  1057.     }
  1058.     while (itemHit != ok && itemHit != cancel);
  1059.     
  1060.     if (itemHit == ok)
  1061.     {
  1062.         GetIText((Handle) cntl[kItem_LineNum], (StringPtr)s1);
  1063.         sscanf(p2cstr((StringPtr)s1) , "%hd", &line_to_go);
  1064.         PinValue(&line_to_go, 0, 32767);
  1065.     }
  1066.     DisposeDialog(myDialog);
  1067.     if (itemHit == ok)
  1068.         goto_line(line_to_go);
  1069.  
  1070.     EnableMenus();
  1071. } // choose_goto_line
  1072.  
  1073.  
  1074. // ---------------------------------------------------------------------
  1075. static void DoLookup()
  1076. {
  1077.     if (FrontWindow() == gSrcWind_Window)
  1078.     {
  1079.         // First, copy the selection to the clipboard
  1080.         ZeroScrap(); // clear out the clipboard
  1081.         TECopy(gSrcWind_TEH);
  1082.         TEToScrap(); // export
  1083.  
  1084.         // Now, switch to POV-Reference if it is there
  1085.  
  1086.     }
  1087. } // DoLookup
  1088.  
  1089.  
  1090. // ---------------------------------------------------------------------
  1091. static OSErr VRef2VolName(short theVRef, StringPtr theVolName)
  1092. {
  1093.     OSErr            anError;
  1094.     HVolumeParam    pbVInfo;
  1095.  
  1096.     pbVInfo.ioCompletion = NULL;
  1097.     theVolName[0] = '\0';
  1098.     pbVInfo.ioNamePtr = theVolName;
  1099.     pbVInfo.ioVRefNum = theVRef;
  1100.     pbVInfo.ioVolIndex = 0; // use VRefNum only
  1101.     anError = PBHGetVInfo((HParmBlkPtr)&pbVInfo, false);
  1102.  
  1103.     return anError;
  1104. } // VRef2VolName
  1105.  
  1106.  
  1107. // ---------------------------------------------------------------------
  1108. static OSErr VolName2VRef(StringPtr myPVolName, short * theVRefPtr)
  1109. {
  1110.     OSErr            anError = noErr;
  1111.     Boolean            foundIt = false;
  1112.     short            theDriveNum;
  1113.     short            theVRefNum;
  1114.     HParamBlockRec    aParamBlk;
  1115.     char            myCVolName[31];
  1116.     Str31            theVolName;
  1117.  
  1118.     // convert passed vol name from P 2 C string for compare
  1119.     BlockMove(myPVolName, myCVolName, myPVolName[0]+1);
  1120.     p2cstr((StringPtr)myCVolName);
  1121.  
  1122.     // loop through all mounted volumes, see if myPVolName matches one
  1123.     for (theDriveNum = 1; !foundIt && (anError==noErr); theDriveNum++)
  1124.     {
  1125.         theVolName[0] = '\0';
  1126.         aParamBlk.volumeParam.ioNamePtr = (StringPtr)&theVolName;
  1127.         aParamBlk.volumeParam.ioVolIndex = theDriveNum;
  1128.         
  1129.         anError = PBHGetVInfoSync((HParmBlkPtr)&aParamBlk);
  1130.         if (anError == noErr)
  1131.         {
  1132.             p2cstr(theVolName);
  1133.             if (strcmp((char*)theVolName, myCVolName)==0)
  1134.             {
  1135.                 foundIt = true;
  1136.                 theVRefNum = aParamBlk.volumeParam.ioVRefNum;
  1137.             }
  1138.         }
  1139.     }
  1140.  
  1141.     if (foundIt)
  1142.         *theVRefPtr = theVRefNum;
  1143.     else
  1144.         *theVRefPtr = 0;
  1145.  
  1146.     if (anError == nsvErr) // no such vol, just bumped end of volume list
  1147.         anError = noErr;
  1148.  
  1149.     return anError;
  1150. } // VolName2VRef
  1151.  
  1152.  
  1153. // ---------------------------------------------------------------------
  1154. static Boolean PromptForSearchPath(FSSpecPtr theDirFSSpecPtr)
  1155. {
  1156.     OSErr        anError;
  1157.     short        trueVRef;
  1158.     long        trueDirID;
  1159.     OSType        wdProcID;
  1160.     Point        sfWhere;
  1161.     short        numTypes;
  1162.     SFTypeList    myTypes;
  1163.     SFReply        theReply;
  1164.  
  1165.     // prompt for Include files
  1166.     numTypes = 1;
  1167.     myTypes[0] = 'TEXT';
  1168.     GetBestDialogPos(&sfWhere);
  1169.     SFGetFile(sfWhere, "\pFind INCLUDE Files?",
  1170.                 0L, numTypes, myTypes, 0L, &theReply);
  1171.  
  1172.     if (!theReply.good)
  1173.         return false;
  1174.     else
  1175.     {
  1176.         // Convert dorky old Working directory into more useful Vref/DirID
  1177.         anError = GetWDInfo(theReply.vRefNum, &trueVRef, &trueDirID, (long*)&wdProcID);
  1178.         // remember dir id & vref
  1179.         theDirFSSpecPtr->vRefNum = trueVRef;
  1180.         theDirFSSpecPtr->parID = trueDirID;
  1181.         // convert transient vref to more permanent volume name
  1182.         VRef2VolName(trueVRef, theDirFSSpecPtr->name);
  1183.         return true;
  1184.     }
  1185. } // PromptForSearchPath
  1186.  
  1187.  
  1188. // ---------------------------------------------------------------------
  1189. /*
  1190. Function:    PathNameFromDirID
  1191.  
  1192. Parameters:
  1193.     aDirID        the directory ID to start at
  1194.     avRefNum    the volume ref # to start at
  1195.     aPathStyle    The style of pathname to format (based on OS)
  1196.     aPath        the final path string is placed in this buffer
  1197.  
  1198. Return Value:
  1199.     zero is returned if OK, else an error is returned
  1200.  
  1201. Purpose/Description:
  1202.     PathNameFromDirID takes a real vRefNum and a DirID and returns
  1203.     the full pathname that corresponds to it.  It does this by calling
  1204.     _PBGetCatInfo for the given directory and finding out its name and
  1205.     the DirID of its parent. It then performs the same operation on the
  1206.     parent, sticking its name onto the beginning of the first directory.
  1207.     This whole process is continued until we have processed everything up
  1208.     to the root directory (identified with a DirID of 2). 
  1209. */
  1210. OSErr PathNameFromDirID(const long            aDirID,
  1211.                         const short            avRefNum,
  1212.                         char                * aPath)
  1213. {
  1214.     Handle        strHandle = NULL;
  1215.     OSErr        anError = noErr;
  1216.     long        currDirID = 0,
  1217.                 nextDirID = 0;
  1218.     Size        theLen = 0;
  1219.     char        tempName[64];    // directory or volume name
  1220.     CInfoPBRec    aPBblock;
  1221.  
  1222.     /* create an empty string handle for Munger */
  1223.     strHandle = NewHandle(0);
  1224.  
  1225.     if (strHandle == NULL)
  1226.     {
  1227.         anError = MemError();
  1228.     }
  1229.     else
  1230.     {
  1231.         *aPath = '\0';
  1232.         aPBblock.dirInfo.ioCompletion    = NULL;
  1233.         aPBblock.dirInfo.ioNamePtr        = (StringPtr)tempName;    // temp destination buffer
  1234.         nextDirID                        = aDirID;    // start at DirID passed in..
  1235.  
  1236.         /* walk up the directories, collecting dir names as we go, until we hit the top (volname) */
  1237.         do {
  1238.             
  1239.             aPBblock.dirInfo.ioVRefNum        = avRefNum;
  1240.             aPBblock.dirInfo.ioFDirIndex    = -1; // ignore ioNamePtr input, use ioDirID
  1241.             aPBblock.dirInfo.ioDrDirID        = nextDirID;
  1242.  
  1243.             anError = PBGetCatInfo(&aPBblock,false);
  1244.             currDirID    = aPBblock.dirInfo.ioDrDirID;    // remember current
  1245.             nextDirID    = aPBblock.dirInfo.ioDrParID;    // find parent for next loop
  1246.  
  1247.             if (anError != noErr)
  1248.                 break;
  1249.  
  1250.             /* Insert a separator in front of the Directory Entry */
  1251.             Munger(strHandle, 0L, NULL, 0L, ":", 1L);
  1252.  
  1253.             /* Insert the next directory/volume name into the front of the string */
  1254.             Munger(strHandle, 0L, NULL, 0L, &(tempName[1]), (long)tempName[0]);
  1255.  
  1256.             /* NOTE: fsRtDirID is defined in Files.h */
  1257.         } while (currDirID != fsRtDirID);
  1258.  
  1259.         /* now move the string into the parameter */
  1260.         theLen = GetHandleSize(strHandle);
  1261.         if (!anError && theLen)
  1262.         {
  1263.             BlockMove(&(**strHandle), aPath, theLen);
  1264.             anError = MemError();
  1265.         }
  1266.         aPath[theLen] = '\0';    /* set C string length */
  1267.     
  1268.         /* dispose of temp storage */
  1269.         DisposeHandle(strHandle);
  1270.  
  1271.     } /*else NULL*/
  1272.  
  1273.     return(anError);
  1274.  
  1275. } /* PathNameFromDirID */
  1276.  
  1277.  
  1278. // ---------------------------------------------------------------------
  1279. /*
  1280. Function:    PathNameFromWD
  1281.  
  1282. Parameters:
  1283.     avRefNum    the volume ref # to start at (Assumes WD is set)
  1284.     aPathStyle    The style of pathname to format (based on OS)
  1285.     aPath        the final path string is placed in this buffer
  1286.  
  1287. Return Value:
  1288.     Describe the value returned, or void
  1289.  
  1290. Purpose/Description:
  1291.     PathNameFromWD takes an HFS Working Directory ID and returns
  1292.     the full pathname that corresponds to it.  It does this by calling
  1293.     _PBGetWDInfo to get the vRefNum and DirID of the real directory.
  1294.     It then calls PathNameFromDirID and returns its result.  
  1295. */
  1296. OSErr PathNameFromWD(    const short            avRefNum,
  1297.                         char                * aPath)
  1298. {
  1299.     WDPBRec    aPBblock;
  1300.     OSErr    anError    = noErr;
  1301.  
  1302.     /*
  1303.     /* PBGetWDInfo has a bug under A/UX 1.1.  If vRefNum is a real vRefNum
  1304.     /* and not a wdRefNum, then it returns garbage.  Since A/UX has only 1
  1305.     /* volume (in the Macintosh sense) and only 1 root directory, this can
  1306.     /* occur only when a file has been selected in the root directory (/).
  1307.     /* So we look for this and hard code the DirID and vRefNum. */
  1308. #if defined(AUX)
  1309.     if ((aPathStyle == ePathTypeAUX) && (avRefNum == -1))
  1310.     {
  1311.         anError = PathNameFromDirID(fsRtDirID, -1, aPath);
  1312.     }
  1313.     else
  1314. #endif
  1315.     {
  1316.         aPBblock.ioCompletion = NULL;
  1317.         aPBblock.ioNamePtr = NULL;
  1318.         aPBblock.ioVRefNum = avRefNum;
  1319.         aPBblock.ioWDIndex = 0;
  1320.         aPBblock.ioWDProcID = 0;
  1321.     
  1322.         /* Change the Working Directory number in vRefnum into a real vRefnum */
  1323.         /* and DirID. The real vRefnum is returned in ioVRefnum, and the real */
  1324.         /* DirID is returned in ioWDDirID. */
  1325.     
  1326.         anError = PBGetWDInfo(&aPBblock,false);
  1327.         if (anError == noErr)
  1328.             anError = PathNameFromDirID(aPBblock.ioWDDirID,
  1329.                                         aPBblock.ioWDVRefNum,
  1330.                                         aPath);
  1331.     }
  1332.  
  1333.     return(anError);
  1334.  
  1335. } /* PathNameFromWD */
  1336.  
  1337.  
  1338.  
  1339. // ---------------------------------------------------------------------
  1340. // Find and open the Application Prefs file
  1341. static OSErr OpenAppPrefs(void)
  1342. {
  1343.     long        theResponse;        /* For call to Gestalt */
  1344.     OSErr        errCode;
  1345.     long        prefs_dirID;
  1346.     short        prefs_volNum;
  1347.      SysEnvRec    theWorld;
  1348.  
  1349.     /* default in case neither FindFolder nor SysEnvirons can help locate the Preference Folder */
  1350.     prefs_dirID = 0;
  1351.     prefs_volNum = 0;
  1352.     
  1353.     errCode = -1;
  1354.     /* Find the preferences folder */
  1355.     errCode = Gestalt(gestaltFindFolderAttr, &theResponse);
  1356.     
  1357.     if (errCode == noErr && (BitTst((Ptr)&theResponse, 31 - gestaltFindFolderPresent)))
  1358.       errCode = FindFolder(kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
  1359.          &prefs_volNum, &prefs_dirID);
  1360.  
  1361.     if (errCode)
  1362.     {
  1363.         /* Error locating the preferences folder, so use the blessed folder */
  1364.         if ((errCode = SysEnvirons(1, &theWorld)) == noErr)
  1365.             prefs_volNum = theWorld.sysVRefNum;
  1366.         else
  1367.             /* Had a problem with SysEnvirons, try the default volume */
  1368.             prefs_volNum = 0;
  1369.         prefs_dirID = 0;
  1370.     }
  1371.  
  1372.     /* Create the prefs file.  If it's already created, no need to create the resource fork. */
  1373.     if ((errCode = HCreate(prefs_volNum, prefs_dirID, POV_RAY_PREFS_FNAME,
  1374.      kAppSignature, kPrefsFileType)) == noErr)
  1375.     {
  1376.         HCreateResFile(prefs_volNum, prefs_dirID, POV_RAY_PREFS_FNAME);
  1377.         errCode = ResError();
  1378.     }
  1379.  
  1380.     /* Return an error code */
  1381.     if (errCode == dupFNErr) /* file's already created?  Not an error. */
  1382.         errCode = noErr;
  1383.     if (errCode == noErr)
  1384.     {
  1385.         AppPrefsRefNum = HOpenResFile(prefs_volNum, prefs_dirID, POV_RAY_PREFS_FNAME, fsRdWrPerm);
  1386.            if (AppPrefsRefNum == kRsrcFileClosed)
  1387.                errCode = kRsrcFileClosed;
  1388.            if (ResError())
  1389.                errCode = ResError();
  1390.        }
  1391.     return errCode;
  1392. } // OpenAppPrefs
  1393.  
  1394.  
  1395.  
  1396. // ---------------------------------------------------------------------
  1397. // Close the Application Prefs file
  1398. static void CloseAppPrefs(void)
  1399. {
  1400.     CloseResFile (AppPrefsRefNum);
  1401.     AppPrefsRefNum = kRsrcFileClosed;
  1402. } // CloseAppPrefs
  1403.  
  1404.  
  1405.  
  1406. // ---------------------------------------------------------------------
  1407. // Write the prefs resource back to the app prefs file
  1408. static void WriteAppPrefs(void)
  1409. {
  1410.     OSErr                theResError = noErr;
  1411.     file_prefs_hdl_t    tmpFileHandle = NULL;
  1412.     app_prefs_hdl_t        tmpAppHandle = NULL;
  1413.  
  1414.     theResError = OpenAppPrefs();
  1415.  
  1416.     if (theResError == noErr)
  1417.     {
  1418.         UseResFile(AppPrefsRefNum);
  1419.  
  1420.         // as long as there are old prefs resources, delete them..
  1421.         // note that I'm getting by index, so as to get any rsrc id #s..
  1422.         do {
  1423.             // App prefs
  1424.             tmpAppHandle = (app_prefs_hdl_t)Get1IndResource(kAppPrefsRsrc, 1);
  1425.             if (tmpAppHandle != NULL)
  1426.             {
  1427.                 RmveResource((Handle)tmpAppHandle);
  1428.                 UpdateResFile(AppPrefsRefNum);
  1429.                 DisposeHandle((Handle)tmpAppHandle);
  1430.             }
  1431.         } while (tmpAppHandle != NULL);
  1432.         do {
  1433.             // Default File prefs
  1434.             tmpFileHandle = (file_prefs_hdl_t)Get1IndResource(kFilePrefsRsrc, 1);
  1435.             if (tmpFileHandle != NULL)
  1436.             {
  1437.                 RmveResource((Handle)tmpFileHandle);
  1438.                 UpdateResFile(AppPrefsRefNum);
  1439.                 DisposeHandle((Handle)tmpFileHandle);
  1440.             }
  1441.         } while (tmpFileHandle != NULL);
  1442.         
  1443.         /* Create a new app prefs resource to add */
  1444.         tmpAppHandle = (app_prefs_hdl_t)NewHandle(sizeof(app_prefs_rec_t));
  1445.     
  1446.         /* Fill it up and add it to file */
  1447.         if (tmpAppHandle != NULL)
  1448.         {
  1449.             **tmpAppHandle = **gAppPrefs_h;
  1450.             AddResource((Handle)tmpAppHandle, kAppPrefsRsrc, kPrefs_rsrcID, "\pPOV-Ray App Prefs");
  1451.             WriteResource((Handle)tmpAppHandle);
  1452.             theResError = ResError();
  1453.         }
  1454.     
  1455.         /* Create a new default file prefs resource to add */
  1456.         if (theResError == noErr)
  1457.             tmpFileHandle = (file_prefs_hdl_t)NewHandle(sizeof(file_prefs_rec_t));
  1458.     
  1459.         /* Fill it up and add it to file */
  1460.         if ((tmpFileHandle != NULL) && (theResError == noErr))
  1461.         {
  1462.             **tmpFileHandle = **gDefltFilePrefs_h;
  1463.             AddResource((Handle)tmpFileHandle, kFilePrefsRsrc, kPrefs_rsrcID, "\pPOV-Ray Default File Prefs");
  1464.             WriteResource((Handle)tmpFileHandle);
  1465.             theResError = ResError();
  1466.         }
  1467.         UseResFile(AppRefNum);
  1468.     
  1469.         if ((theResError) || (tmpAppHandle == NULL) || (tmpFileHandle == NULL))
  1470.         {
  1471.             // error updating prefs file
  1472.             displayDialog(144, NULL, theResError, ewcDoCentering, eMainDevice);
  1473.             gAppPrefs_h = NULL;
  1474.             exit_handler();
  1475.         }
  1476.  
  1477.         // All done, clean up shop
  1478.         CloseAppPrefs();
  1479.  
  1480.     } // if !error
  1481. } // WriteAppPrefs
  1482.  
  1483.  
  1484.  
  1485. // # of ticks "Updating Prefs" dialog is up
  1486. #define    kUpdPrefsTime    ((long)4*60)
  1487.  
  1488. // ---------------------------------------------------------------------
  1489. // Open the App prefs file & get the prefs out of the file.  If the file
  1490. // is out of date or doesn't exist, create a new one and fill it with defaults.
  1491. static void GetAppPrefs(void)
  1492. {
  1493.     OSErr                theResError = noErr;
  1494.     DialogPtr            updPrefsDialogPtr;
  1495.     file_prefs_hdl_t    tmpFileHandle = NULL;
  1496.     app_prefs_hdl_t        tmpAppHandle = NULL;
  1497.  
  1498.     theResError = OpenAppPrefs();
  1499.  
  1500.     // Get saved prefs for POV_Ray prefs dialog from the app prefs file
  1501.     if (theResError == noErr)
  1502.     {
  1503.         UseResFile(AppPrefsRefNum);
  1504.         theResError = ResError();
  1505.  
  1506.         // read app prefs
  1507.         if (theResError == noErr)
  1508.         {
  1509.             tmpAppHandle = (app_prefs_hdl_t) Get1Resource(kAppPrefsRsrc, kPrefs_rsrcID);
  1510.             theResError = ResError();
  1511.             if (theResError != noErr)
  1512.                 tmpAppHandle = NULL;
  1513.         }
  1514.     
  1515.         // read default file prefs
  1516.         if (theResError == noErr)
  1517.         {
  1518.             tmpFileHandle = (file_prefs_hdl_t) Get1Resource(kFilePrefsRsrc, kPrefs_rsrcID);
  1519.             theResError = ResError();
  1520.             if (theResError != noErr)
  1521.                 tmpFileHandle = NULL;
  1522.         }
  1523.     
  1524.         if (theResError != noErr)
  1525.         {
  1526.             // error creating prefs file
  1527.             (void)displayDialog(145, NULL, theResError, ewcDoCentering, eMainDevice);
  1528.             exit_handler();
  1529.         }
  1530.     
  1531.         // did we get the App prefs?
  1532.         if (tmpAppHandle != NULL)
  1533.         {
  1534.             // Is it the wrong version? Delete it if so..
  1535.             if ((**tmpAppHandle).prefsVersion != kPrefs_rsrcVers)
  1536.             {
  1537.                 RmveResource((Handle)tmpAppHandle);
  1538.                 UpdateResFile(AppPrefsRefNum);
  1539.                 DisposeHandle((Handle)tmpAppHandle);
  1540.                 tmpAppHandle = NULL; // flag code below to add new
  1541.             }
  1542.         }
  1543.     
  1544.         // did we get the Default File prefs?
  1545.         if (tmpFileHandle != NULL)
  1546.         {
  1547.             // Is it the wrong version or did we fail to get App prefs? Delete file prefs if so..
  1548.             if ( ((**tmpFileHandle).prefsVersion != kPrefs_rsrcVers)
  1549.             || (tmpAppHandle == NULL) )
  1550.             {
  1551.                 RmveResource((Handle)tmpFileHandle);
  1552.                 UpdateResFile(AppPrefsRefNum);
  1553.                 DisposeHandle((Handle)tmpFileHandle);
  1554.                 tmpFileHandle = NULL; // flag code below to add new
  1555.             }
  1556.         }
  1557.     
  1558.         // Still got App Prefs?  Use it!
  1559.         if (tmpAppHandle != NULL)
  1560.         {
  1561.             // copy contents from rsrc to our memory buffer
  1562.             **gAppPrefs_h = **tmpAppHandle;
  1563.             ReleaseResource((Handle)tmpAppHandle);
  1564.         }
  1565.  
  1566.         // Still got File Prefs?  Use it!
  1567.         if (tmpFileHandle != NULL)
  1568.         {
  1569.             // copy contents from rsrc to our memory buffer
  1570.             **gDefltFilePrefs_h = **tmpFileHandle;
  1571.  
  1572.             // make sure our windows are visible on THIS MACHINE'S screens
  1573.             ForceRectOnScreen(&(**gDefltFilePrefs_h).srcWind_pos);
  1574.             ForceRectOnScreen(&(**gDefltFilePrefs_h).statWind_pos);
  1575.             ForceRectOnScreen(&(**gDefltFilePrefs_h).imageWind_pos);
  1576.             ReleaseResource((Handle)tmpFileHandle);
  1577.         }
  1578.     
  1579.         // return to app rsrc for dialogs
  1580.         UseResFile(AppRefNum);
  1581.     
  1582.         // All done, clean up shop
  1583.         CloseAppPrefs();
  1584.  
  1585.         // fill & add new ones if we couldn't read or use the old ones
  1586.         if ((tmpAppHandle == NULL) || (tmpFileHandle == NULL))
  1587.         {
  1588.             // didn't get it, tell user what's happening with a little dialog..
  1589.             TargetTicks = TICKS + kUpdPrefsTime;
  1590.             updPrefsDialogPtr = GetNewDialog(147, NULL, (WindowPtr)-1); // updating prefs..
  1591.             if (updPrefsDialogPtr)
  1592.             {
  1593.                 PositionWindow(updPrefsDialogPtr, ewcDoCentering, eMainDevice, (WindowPtr)NULL);
  1594.                 ShowWindow(updPrefsDialogPtr);
  1595.                 SelectWindow(updPrefsDialogPtr);
  1596.                 DrawDialog(updPrefsDialogPtr);
  1597.             }
  1598.  
  1599.             //
  1600.             // --- set global app record to defaults
  1601.             //
  1602.  
  1603.             if (tmpAppHandle == NULL)
  1604.             {
  1605.                 (**gAppPrefs_h).prefsVersion        = kPrefs_rsrcVers;
  1606.                 (**gAppPrefs_h).howMultiFriendly    = kDefMultiFriendly;
  1607.                 (**gAppPrefs_h).whenToNotify        = eWhenNtf_BgFg;
  1608.                 (**gAppPrefs_h).howToNotify            = eHowNtf_Noise;
  1609.  
  1610.                 // Just use current volume name as include directory for now
  1611.                 GetVol((**gAppPrefs_h).includeDirFSSpec.name,
  1612.                         &(**gAppPrefs_h).includeDirFSSpec.vRefNum);
  1613.                 (**gAppPrefs_h).includeDirFSSpec.parID = fsRtDirID;
  1614.  
  1615.             } // if (tmpAppHandle == NULL)
  1616.  
  1617.             //
  1618.             // --- set global default file record to defaults
  1619.             //
  1620.  
  1621.             if (tmpFileHandle == NULL)
  1622.             {
  1623.  
  1624.                 (**gDefltFilePrefs_h).prefsVersion = kPrefs_rsrcVers;
  1625.  
  1626.                 // SOURCE window
  1627.                 SetRect(&(**gDefltFilePrefs_h).srcWind_pos,    // left, top, right, bottom
  1628.                                 qd.screenBits.bounds.left + 2,
  1629.                                 qd.screenBits.bounds.top + GetMBarHeight()+40,
  1630.                                 min(qd.screenBits.bounds.left + 480, qd.screenBits.bounds.right - 40),
  1631.                                 400);
  1632.  
  1633.                 // STATUS window
  1634.                 SetRect(&(**gDefltFilePrefs_h).statWind_pos,    // left, top, right, bottom
  1635.                                 qd.screenBits.bounds.left + 3,
  1636.                                 qd.screenBits.bounds.bottom - 260,
  1637.                                 min(qd.screenBits.bounds.left + 480, qd.screenBits.bounds.right - 40),
  1638.                                 qd.screenBits.bounds.bottom - 20);
  1639.     
  1640.                 // IMAGE window
  1641.                 SetRect(&(**gDefltFilePrefs_h).imageWind_pos,    // left, top, right, bottom
  1642.                                 qd.screenBits.bounds.left + 1,
  1643.                                 qd.screenBits.bounds.top + GetMBarHeight()+20,
  1644.                                 0, 0); // not used
  1645.     
  1646.                 (**gDefltFilePrefs_h).imageWidth = scrnSizeMenu[kDfltScrnSize][0]; // x
  1647.                 (**gDefltFilePrefs_h).imageHeight = scrnSizeMenu[kDfltScrnSize][1]; // y
  1648.                 (**gDefltFilePrefs_h).imageUpperLeft.h = 0;
  1649.                 (**gDefltFilePrefs_h).imageUpperLeft.v = 0;
  1650.  
  1651.                 SetRect(&(**gDefltFilePrefs_h).selectionArea, 1, 1,
  1652.                         (**gDefltFilePrefs_h).imageWidth,
  1653.                         (**gDefltFilePrefs_h).imageHeight);
  1654.  
  1655.                 (**gDefltFilePrefs_h).pictFileCreator    = 'ttxt';
  1656.                 (**gDefltFilePrefs_h).targaFileCreator    = '8BIM';
  1657.  
  1658.                 (**gDefltFilePrefs_h).renderQuality        = 9;
  1659.                 (**gDefltFilePrefs_h).custom_palette    = palette_median;
  1660.                 (**gDefltFilePrefs_h).imageMagFactor    = viewmn_normal;
  1661.  
  1662.                 (**gDefltFilePrefs_h).createTargaOutfile = false;
  1663.                 (**gDefltFilePrefs_h).continueTarga        = false;
  1664.                 (**gDefltFilePrefs_h).doDither            = true;
  1665.                 (**gDefltFilePrefs_h).doBoundSlabs        = false;
  1666.                 (**gDefltFilePrefs_h).boundSlabThreshold= 0;
  1667.                 (**gDefltFilePrefs_h).progress            = kProgNone;
  1668.                 (**gDefltFilePrefs_h).languageVersion    = kMaxLangVersion;
  1669.                 (**gDefltFilePrefs_h).maxSymbolsVal        = kDefaultMaxSym;
  1670.                 
  1671.                 (**gDefltFilePrefs_h).doAnimation        = false;
  1672.                 (**gDefltFilePrefs_h).doCompression        = false;
  1673.                 (**gDefltFilePrefs_h).do24BitPict        = true;
  1674.  
  1675.                 (**gDefltFilePrefs_h).doAntialias        = false;
  1676.                 (**gDefltFilePrefs_h).antialiasThreshold = 0.30;
  1677.                 (**gDefltFilePrefs_h).antialiasDepth    = 3;
  1678.                 (**gDefltFilePrefs_h).antiJitterScale    = 0.0;
  1679.  
  1680.                 // CLOCK - animation    
  1681.                 (**gDefltFilePrefs_h).animRec.frameVal0    = 1;
  1682.                 (**gDefltFilePrefs_h).animRec.frameValN    = 50;
  1683.                 (**gDefltFilePrefs_h).animRec.frameValS    = (**gDefltFilePrefs_h).animRec.frameVal0;
  1684.                 (**gDefltFilePrefs_h).animRec.frameValE    = (**gDefltFilePrefs_h).animRec.frameValN;
  1685.                 (**gDefltFilePrefs_h).animRec.clockVal0    = 0.0;
  1686.                 (**gDefltFilePrefs_h).animRec.clockValN    = 10.0;
  1687.  
  1688.                 // Initial defaults for SC compression dialog    
  1689.                 if (gtheSCComponent)
  1690.                 {
  1691.                     (void)SCGetInfo(gtheSCComponent, scSpatialSettingsType, &(**gDefltFilePrefs_h).sc_DialogParams);
  1692.                 }
  1693.             } // if (tmpFileHandle == NULL)
  1694.  
  1695.             WriteAppPrefs();
  1696.     
  1697.             // if update dialog is up, wait for user to read it, then tear it down
  1698.             if (updPrefsDialogPtr)
  1699.             {
  1700.                 SysBeep(4);
  1701.                 while (TICKS < TargetTicks)
  1702.                     {
  1703.                     }
  1704.                 DisposeDialog(updPrefsDialogPtr);
  1705.             }
  1706.     
  1707.         } // didn't get it, create new
  1708.     
  1709.         // make sure file prefs is initialized too
  1710.         **gFilePrefs_h = **gDefltFilePrefs_h; // initialize this to defaults
  1711.     
  1712.         // set up our current prefs to be those of the file.
  1713.         // This can be changed with the App Prefs dialog
  1714.         gPrefs2Use_h = gFilePrefs_h;
  1715.  
  1716.     }
  1717. } // GetAppPrefs
  1718.  
  1719.  
  1720.  
  1721. // ---------------------------------------------------------------------
  1722. // Open a source file's resource fork for getting/putting settings info
  1723. static void OpenFilePrefs(void)
  1724. {
  1725.     if (gSrcWind_VRefNum != 0)    // if there is a file open..
  1726.     {
  1727.         SetVol(NULL, gSrcWind_VRefNum);
  1728.         if (SrcResRefNum != kRsrcFileClosed)
  1729.             printf("## ERROR! opening already-opened rsrc file: OpenFilePrefs()\n");
  1730.         SrcResRefNum = OpenResFile(gSrcWind_FileName);
  1731.         if (SrcResRefNum == kRsrcFileClosed)
  1732.         {
  1733.             CreateResFile(gSrcWind_FileName);
  1734.             SrcResRefNum = OpenResFile(gSrcWind_FileName);
  1735.         }
  1736.     }
  1737. } // OpenFilePrefs
  1738.  
  1739.  
  1740.  
  1741. // ---------------------------------------------------------------------
  1742. // Close the source file's resource fork
  1743. static void CloseFilePrefs(void)
  1744. {
  1745.     if (SrcResRefNum != kRsrcFileClosed)
  1746.         CloseResFile(SrcResRefNum);
  1747.     SrcResRefNum = kRsrcFileClosed;
  1748. } // CloseFilePrefs
  1749.  
  1750.  
  1751.  
  1752. // ---------------------------------------------------------------------
  1753. // Update the source file's settings info
  1754. void WriteFilePrefs(void)
  1755. {
  1756.     file_prefs_hdl_t    tmpFilePrefsHandle;
  1757.  
  1758.     if (SrcResRefNum == kRsrcFileClosed)
  1759.         OpenFilePrefs();
  1760.  
  1761.     if (SrcResRefNum != kRsrcFileClosed)
  1762.     {
  1763.         /* switch over to our open file */
  1764.         UseResFile(SrcResRefNum);
  1765.  
  1766.         /* as long as there are old file prefs resources, delete them */
  1767.         do {
  1768.             tmpFilePrefsHandle = (file_prefs_hdl_t)Get1IndResource(kFilePrefsRsrc, 1);
  1769.             if (tmpFilePrefsHandle != NULL)
  1770.             {
  1771.                 RmveResource((Handle)tmpFilePrefsHandle);
  1772.                 UpdateResFile(SrcResRefNum);
  1773.                 DisposeHandle((Handle)tmpFilePrefsHandle);
  1774.             }
  1775.         } while (tmpFilePrefsHandle != NULL);
  1776.  
  1777.         /* Create a new resource to add */
  1778.         tmpFilePrefsHandle = (file_prefs_hdl_t)NewHandle(sizeof(file_prefs_rec_t));
  1779.  
  1780.         /* Fill it up and add it to file */
  1781.         if (tmpFilePrefsHandle != NULL)
  1782.         {
  1783.             **tmpFilePrefsHandle = **gFilePrefs_h;
  1784.             AddResource((Handle)tmpFilePrefsHandle, kFilePrefsRsrc, kPrefs_rsrcID, "\pPOV-Ray File Prefs");
  1785.             WriteResource((Handle)tmpFilePrefsHandle);
  1786.             ReleaseResource((Handle)tmpFilePrefsHandle);
  1787.         }
  1788.         CloseFilePrefs();
  1789.         UseResFile(AppRefNum);
  1790.     } // if opened
  1791. } // WriteFilePrefs
  1792.  
  1793.  
  1794.  
  1795. // ---------------------------------------------------------------------
  1796. // Get the setting info from the source file
  1797. static void GetFilePrefs(void)
  1798. {
  1799.     file_prefs_hdl_t    tmpFilePrefsHandle = NULL;
  1800.  
  1801.     if (SrcResRefNum == kRsrcFileClosed)
  1802.         OpenFilePrefs();
  1803.  
  1804.     if (SrcResRefNum != kRsrcFileClosed)
  1805.         tmpFilePrefsHandle = (file_prefs_hdl_t)Get1Resource(kFilePrefsRsrc, kPrefs_rsrcID);
  1806.  
  1807.     if (tmpFilePrefsHandle != NULL)
  1808.     {
  1809.         /* Is it the wrong version? */
  1810.         if ((**tmpFilePrefsHandle).prefsVersion != kPrefs_rsrcVers)
  1811.         {    /* old version, delete & create new one below! */
  1812.             RmveResource((Handle)tmpFilePrefsHandle);
  1813.             UpdateResFile(SrcResRefNum);
  1814.             DisposeHandle((Handle)tmpFilePrefsHandle);
  1815.             tmpFilePrefsHandle = NULL; /* flag code below to add new */
  1816.         }
  1817.         /* Still got it?  Use it! */
  1818.         if (tmpFilePrefsHandle != NULL)
  1819.         {
  1820.             **gFilePrefs_h = **tmpFilePrefsHandle;
  1821.             /* make sure our windows are on THIS MACHINE'S screens */
  1822.             ForceRectOnScreen(&(**gFilePrefs_h).srcWind_pos);
  1823.             ForceRectOnScreen(&(**gFilePrefs_h).statWind_pos);
  1824.             ForceRectOnScreen(&(**gFilePrefs_h).imageWind_pos);
  1825.  
  1826.             if ((**gDefltFilePrefs_h).progress >= kProgDebug)
  1827.             {
  1828.                 printf("-d GetFilePrefs():\n");
  1829.                 printf("-d   ImageWind = <%d, %d, %d, %d>\n",
  1830.                     (**gFilePrefs_h).imageWind_pos.left,
  1831.                     (**gFilePrefs_h).imageWind_pos.top,
  1832.                     (**gFilePrefs_h).imageWind_pos.right,
  1833.                     (**gFilePrefs_h).imageWind_pos.bottom);
  1834.                 printf("-d   srcWind = <%d, %d, %d, %d>\n",
  1835.                     (**gFilePrefs_h).srcWind_pos.left,
  1836.                     (**gFilePrefs_h).srcWind_pos.top,
  1837.                     (**gFilePrefs_h).srcWind_pos.right,
  1838.                     (**gFilePrefs_h).srcWind_pos.bottom);
  1839.             }
  1840.  
  1841.         }
  1842.     }
  1843.  
  1844.     /* create a new one if can't read or use the old one */
  1845.     if (tmpFilePrefsHandle == NULL)
  1846.     {
  1847.         **gFilePrefs_h = **gDefltFilePrefs_h;    // get default settings
  1848.         WriteFilePrefs();
  1849.     }
  1850.     else
  1851.         ReleaseResource((Handle)tmpFilePrefsHandle);
  1852. } // GetFilePrefs
  1853.  
  1854.  
  1855. //
  1856. // POV-Ray Prefs Dialog items
  1857. //
  1858. #define    kPU_HowMFFriendlyPopup            4
  1859. #define    kRB_UseDefaultAppPrefs            5
  1860. #define    kRB_UseDefaultFilePrefs            6
  1861. #define    kPU_NotifyPopup                    7
  1862. #define    kPU_NotifyStylePopup            8
  1863. #define    kBT_SetSearchPath                9
  1864. #define    kST_SearchPath                    11
  1865. #define    k_LastItem                    kST_SearchPath
  1866. #define    kRsrc_HowMultiFriendlyMenuID    300
  1867. #define    kRsrc_NotifyMenuID                303
  1868. #define    kRsrc_NotifyStyleMenuID            304
  1869.  
  1870. // ---------------------------------------------------------------------
  1871. // Prompt the user to change the Application Preferences
  1872. static void ChangeAppPrefs(void)
  1873. {
  1874.     short            i, dummyInt;
  1875.     short            itemHit;
  1876.     DialogPtr        myDialog;
  1877.     Rect            displayRect;
  1878.     ControlHandle    cntl[k_LastItem+1];
  1879.     app_prefs_rec_t    thePrefs;
  1880.     popupRec_t        aPopupRec;
  1881.     Str255            thePath;
  1882.  
  1883.     myDialog = GetNewDialog(131, NULL, (WindowPtr) -1);
  1884.     if (!myDialog)
  1885.     {
  1886.         SysBeep(4);
  1887.         return;
  1888.     }
  1889.  
  1890.     DisableMenus();
  1891.     
  1892.     // update temporary prefs record until user clicks OK!
  1893.     thePrefs = **gAppPrefs_h;
  1894.  
  1895.     for (i = 1; i <= k_LastItem; i++)
  1896.         GetDItem(myDialog, i, &dummyInt, (Handle *) &cntl[i], &displayRect);
  1897.  
  1898.     // init the popup menus
  1899.     InitPopups();
  1900.  
  1901.     // Add the Multifriendliness popup
  1902.     aPopupRec.fParentDialog    = myDialog;
  1903.     aPopupRec.fMenuID        = kRsrc_HowMultiFriendlyMenuID;
  1904.     aPopupRec.fPopupItemID    = kPU_HowMFFriendlyPopup;
  1905.     aPopupRec.fLastChoice    = thePrefs.howMultiFriendly;
  1906.     AddPopupToList(&aPopupRec);
  1907.  
  1908.     // Add the Notify & Notify Style popups
  1909.     aPopupRec.fParentDialog    = myDialog;
  1910.     aPopupRec.fMenuID        = kRsrc_NotifyMenuID;
  1911.     aPopupRec.fPopupItemID    = kPU_NotifyPopup;
  1912.     aPopupRec.fLastChoice    = (short)thePrefs.whenToNotify+1;
  1913.     AddPopupToList(&aPopupRec);
  1914.  
  1915.     aPopupRec.fParentDialog    = myDialog;
  1916.     aPopupRec.fMenuID        = kRsrc_NotifyStyleMenuID;
  1917.     aPopupRec.fPopupItemID    = kPU_NotifyStylePopup;
  1918.     aPopupRec.fLastChoice    = (short)thePrefs.howToNotify+1;
  1919.     AddPopupToList(&aPopupRec);
  1920.  
  1921.     // convert volume name to vref for making full path
  1922.     VolName2VRef(thePrefs.includeDirFSSpec.name,
  1923.                 &thePrefs.includeDirFSSpec.vRefNum);
  1924.     // make full path
  1925.     PathNameFromDirID(thePrefs.includeDirFSSpec.parID, thePrefs.includeDirFSSpec.vRefNum, (char*)thePath);
  1926.     c2pstr((char*)thePath);
  1927.     // stuff path into display field
  1928.     SetIText((Handle) cntl[kST_SearchPath], thePath);
  1929.  
  1930.     PositionWindow(myDialog, ewcDoCentering, eSameAsPassedWindow, (WindowPtr)gp2wWindow);
  1931.  
  1932.     /* "default" the OK button */
  1933.     SetupDefaultButton(myDialog);
  1934.     SetCursor(&qd.arrow);
  1935.     ShowWindow(myDialog);
  1936.  
  1937.     do
  1938.     {
  1939.         // Set the Use App/File prefs RBs
  1940.         SetCtlValue(cntl[kRB_UseDefaultAppPrefs],    gUseAppDefaultPrefs);
  1941.         SetCtlValue(cntl[kRB_UseDefaultFilePrefs],    !gUseAppDefaultPrefs);
  1942.  
  1943. #if defined(__powerc)
  1944.         ModalDialog((ModalFilterUPP)&gModalFilterRD, &itemHit);
  1945. #else
  1946.         ModalDialog((ModalFilterProcPtr)ModalFilter, &itemHit);
  1947. #endif // __powerc
  1948.         switch (itemHit)
  1949.         {
  1950.             case kRB_UseDefaultAppPrefs:
  1951.                 gUseAppDefaultPrefs = true;
  1952.                 break;
  1953.  
  1954.             case kRB_UseDefaultFilePrefs:
  1955.                 gUseAppDefaultPrefs = false;
  1956.                 break;
  1957.  
  1958.             case kBT_SetSearchPath:
  1959.                 // Call up Standard File to let user find the path
  1960.                 if (PromptForSearchPath(&thePrefs.includeDirFSSpec))
  1961.                 {
  1962.                     PathNameFromDirID(thePrefs.includeDirFSSpec.parID, thePrefs.includeDirFSSpec.vRefNum, (char*)thePath);
  1963.                     c2pstr((char*)thePath);
  1964.                     SetIText((Handle) cntl[kST_SearchPath], thePath);
  1965.                 }
  1966.                 break;
  1967.         }
  1968.     }
  1969.     while ((itemHit != ok) && (itemHit != cancel));
  1970.  
  1971.     if (itemHit == ok)
  1972.     {
  1973.         thePrefs.howMultiFriendly = GetPopupValue(kPU_HowMFFriendlyPopup);
  1974.         gCpuHogginess = thePrefs.howMultiFriendly;
  1975.         CalcCpuReleaseTicks(true);
  1976.  
  1977.         // find When notification
  1978.         thePrefs.whenToNotify = (WhenNotify_t)GetPopupValue(kPU_NotifyPopup)-1;
  1979.  
  1980.         // find How notification
  1981.         thePrefs.howToNotify = (HowNotify_t)GetPopupValue(kPU_NotifyStylePopup)-1;
  1982.  
  1983.         // Change which rendering prefs to use
  1984.         if (gUseAppDefaultPrefs)
  1985.             gPrefs2Use_h = gDefltFilePrefs_h;
  1986.         else
  1987.             gPrefs2Use_h = gFilePrefs_h;
  1988.  
  1989.         // fill in the prefs with new values
  1990.         **gAppPrefs_h = thePrefs;
  1991.  
  1992.         // save prefs in file if OK
  1993.         WriteAppPrefs();
  1994.     }
  1995.  
  1996.     // all done with the popup menus
  1997.     KillPopups();
  1998.  
  1999.     SetCursor(&qd.arrow);
  2000.  
  2001.     // get rid of the dialog
  2002.     DisposeDialog(myDialog);
  2003.  
  2004.     EnableMenus();
  2005. } // ChangeAppPrefs
  2006.  
  2007.  
  2008.  
  2009. //
  2010. // Rendering Options Dialog items
  2011. //
  2012. #define    kST_Filename            4
  2013. #define    kET_fImageWidth            5
  2014. #define    kET_fImageHeight        6
  2015. #define    kET_fRowFrom            7
  2016. #define    kET_fRowTo                8
  2017. #define    kPU_fImageQuality        9
  2018. #define    kCB_fAntiAliasCheck        10
  2019. #define    kPU_fTAntiAliasThresh    11
  2020. #define    kET_fAntiAliasThresh    12
  2021. #define    kST_fTAntialiasDepth    13
  2022. #define    kST_fAntialiasDepth        14
  2023. #define    kST_fTAntiJitterScale    15
  2024. #define    kET_fAntiJitterScale    16
  2025. #define    kUU_fAntiAliasDummyItem    17
  2026. #define kPU_fProgress            18
  2027. #define    kPU_fMaxBounds            19
  2028. #define    kCB_fAnimate            20
  2029. #define    kBT_fAnimSettings        21
  2030. #define kPU_fLangVersion        22
  2031. #define    kCB_fDoPICTCmp            23
  2032. #define    kBT_fPICTCmpSettings    24
  2033. #define    kPU_fMaxSyms            25
  2034. #define    kCB_fCreateTarga        26
  2035. #define    kCB_fContinueFromTarga    27
  2036. #define    kPU_fImageSize            28
  2037. #define    kCB_SaveAsDefault        29
  2038. #define    kItem_fLastItem            kCB_SaveAsDefault
  2039.  
  2040. #define    kMenuID_fImageQuality    301
  2041. #define    kMenuID_fImageSize        302
  2042. #define    kMenuID_fMaxSym            305
  2043. #define    kMenuID_fLangVersion    306
  2044. #define    kMenuID_fProgress        307
  2045. #define    kMenuID_fMaxBounds        308
  2046.  
  2047.  
  2048. // ---------------------------------------------------------------------
  2049. // dim a rectangular area of a window
  2050. static void erase_TE_rect(WindowPtr dlgWindPtr, Rect *pRect)
  2051. {
  2052. #pragma unused (dlgWindPtr)
  2053.     PenState    thePen;
  2054.     Rect        outerRect;
  2055.  
  2056.     // Save and restore the pen state so we don't mess things up
  2057.     // for other drawing routines
  2058.     GetPenState(&thePen);
  2059.  
  2060.     outerRect = *pRect;
  2061.     InsetRect(&outerRect, -3, -3); // border outside TE item
  2062.     ForeColor(whiteColor);
  2063.     FrameRect(&outerRect);
  2064.  
  2065.     SetPenState(&thePen);
  2066.     ForeColor(blackColor);
  2067. }
  2068.  
  2069.  
  2070. // ---------------------------------------------------------------------
  2071. // dim a rectangular area of a window
  2072. static void dim_rect(WindowPtr dlgWindPtr, Rect *pRect)
  2073. {
  2074. #pragma unused (dlgWindPtr)
  2075.     PenState    thePen;
  2076.  
  2077.     // Save and restore the pen state so we don't mess things up
  2078.     // for other drawing routines
  2079.     GetPenState(&thePen);
  2080.     PenMode(notPatBic);
  2081.  
  2082.     PenPat((ConstPatternParam)&qd.gray);
  2083.     PaintRect(pRect);
  2084.  
  2085.     SetPenState(&thePen);
  2086. }
  2087.  
  2088.  
  2089. // ---------------------------------------------------------------------
  2090. // dim/enable the aa edit text fields
  2091. static void update_edit_text(WindowPtr dlgWindPtr)
  2092. {
  2093. #define    MAX_TE_CONTROLS            3    // size of theTEControlH array
  2094.  
  2095.     Boolean            aaCheckBox;
  2096.     int                k;
  2097.     short int        itemType;
  2098.     GrafPtr            saveGP;
  2099.     Rect            aRect;
  2100.     ControlHandle    theAAControlH;
  2101.     ControlHandle    theTEControlH[MAX_TE_CONTROLS];
  2102.     short int        theTEitem[MAX_TE_CONTROLS];
  2103.  
  2104.     GetPort(&saveGP);
  2105.     SetPort(dlgWindPtr);
  2106.  
  2107.     // What is the state of the aa checkbox now?
  2108.     GetDItem(dlgWindPtr, kCB_fAntiAliasCheck, &itemType, (Handle*)&theAAControlH, &aRect);
  2109.     aaCheckBox = GetCtlValue(theAAControlH);
  2110.  
  2111.     // Get the actual TE items
  2112.     theTEitem[0] = kET_fAntiAliasThresh;
  2113.     theTEitem[1] = kST_fAntialiasDepth;
  2114.     theTEitem[2] = kET_fAntiJitterScale;
  2115.     GetDItem(dlgWindPtr, theTEitem[0], &itemType, (Handle*)&(theTEControlH[0]), &aRect);
  2116.     GetDItem(dlgWindPtr, theTEitem[1], &itemType, (Handle*)&(theTEControlH[1]), &aRect);
  2117.     GetDItem(dlgWindPtr, theTEitem[2], &itemType, (Handle*)&(theTEControlH[2]), &aRect);
  2118.  
  2119.     // dim/enable each TE item
  2120.     for (k=0; k<MAX_TE_CONTROLS; k++)
  2121.         if (aaCheckBox)
  2122.         {    // aa is ON, set to enabled EditText item
  2123.             // enable TE
  2124.             GetDItem(dlgWindPtr, theTEitem[k], &itemType, (Handle*)&(theTEControlH[k]), &aRect);
  2125.              SetDItem(dlgWindPtr, theTEitem[k], editText, (Handle)theTEControlH[k], &aRect);
  2126.             // invalidate TEs so they are redrawn
  2127.             InsetRect(&aRect, -5, -5); // just outside TE item
  2128.             InvalRect(&aRect);
  2129.         }
  2130.         else
  2131.         {    // aa is OFF, disable & dim TE item
  2132.  
  2133.             // If current text edit cursor inside dimmed TE...
  2134.             if    ( ((DialogPeek)dlgWindPtr)->editField == theTEitem[k]-1 )
  2135.             {
  2136.                 // bump it back to beginning edit text field
  2137.                 SelIText(dlgWindPtr, kET_fImageWidth, 0, 0);
  2138.             }
  2139.  
  2140.             // make it think it is a static text item, not EditText
  2141.             GetDItem(dlgWindPtr, theTEitem[k], &itemType, (Handle*)&(theTEControlH[k]), &aRect);
  2142.              erase_TE_rect(dlgWindPtr, &aRect);
  2143.             SetDItem(dlgWindPtr, theTEitem[k], statText+itemDisable, (Handle)(theTEControlH[k]), &aRect);
  2144.  
  2145.             InsetRect(&aRect, -5, -5); // just outside TE item
  2146.             InvalRect(&aRect);
  2147.         } // else off
  2148.  
  2149.     SetPort(saveGP);
  2150.  
  2151. } // update_edit_text
  2152.  
  2153.  
  2154.  
  2155. // ---------------------------------------------------------------------
  2156. // Determine closest index in the scrnSizeMenu array to the h/v passed
  2157. static short GetClosestImageSizeItem(short pWidth, short pHeight)
  2158. {
  2159.     int        k;
  2160.  
  2161.     // go down the list & find a match
  2162.     for (k=0; k<SCRN_SIZE_MENU_MAX; k++)
  2163.     {
  2164.         if ((scrnSizeMenu[k][0] >= pWidth) && (scrnSizeMenu[k][1] >= pHeight))
  2165.             return k+1;    // return item #
  2166.     }
  2167.  
  2168.     // off the scale, return max
  2169.     return SCRN_SIZE_MENU_MAX;
  2170.  
  2171. } // GetClosestImageSizeItem
  2172.  
  2173.  
  2174.  
  2175. // ---------------------------------------------------------------------
  2176. // Prompt the user to change the file settings
  2177. static void ChangeFilePrefs(void)
  2178. {
  2179.     short                itemHit;
  2180.     short                i, dummyInt;
  2181.     DialogPtr            myDialog;
  2182.     Rect                displayRect;
  2183.     file_prefs_rec_t    thePrefs;
  2184.     ControlHandle        cntl[kItem_fLastItem+1];
  2185.     char                s1[256];
  2186.     popupRec_t            aPopupRec;
  2187.  
  2188.     myDialog = GetNewDialog(128, NULL, (WindowPtr) -1);
  2189.     if (!myDialog)
  2190.     {
  2191.         SysBeep(4);
  2192.         return;
  2193.     }
  2194.  
  2195.     DisableMenus();
  2196.     
  2197.     // update temporary prefs record until user clicks OK!
  2198.     thePrefs = **gFilePrefs_h;
  2199.  
  2200.     for (i = 1; i <= kItem_fLastItem; i++)
  2201.         GetDItem(myDialog, i, &dummyInt, (Handle *) &cntl[i], &displayRect);
  2202.  
  2203.     SetIText((Handle) cntl[kST_Filename], gSrcWind_FileName);
  2204.  
  2205.     // init the popup menus
  2206.     InitPopups();
  2207.  
  2208.     // Add the Image Quality popup
  2209.     aPopupRec.fParentDialog    = myDialog;
  2210.     aPopupRec.fMenuID        = kMenuID_fImageQuality;
  2211.     aPopupRec.fPopupItemID    = kPU_fImageQuality;
  2212.     aPopupRec.fLastChoice    = thePrefs.renderQuality+1;
  2213.     AddPopupToList(&aPopupRec);
  2214.  
  2215.     // Add the Image Size Presets popup
  2216.     aPopupRec.fParentDialog    = myDialog;
  2217.     aPopupRec.fMenuID        = kMenuID_fImageSize;
  2218.     aPopupRec.fPopupItemID    = kPU_fImageSize;
  2219.     aPopupRec.fLastChoice    = GetClosestImageSizeItem(thePrefs.imageWidth, thePrefs.imageHeight);
  2220.     AddPopupToList(&aPopupRec);
  2221.  
  2222.     // Add the Auto Bounds popup
  2223.     aPopupRec.fParentDialog    = myDialog;
  2224.     aPopupRec.fMenuID        = kMenuID_fMaxBounds;
  2225.     aPopupRec.fPopupItemID    = kPU_fMaxBounds;
  2226.     if (thePrefs.doBoundSlabs)
  2227.         // off, ---, 1, 5, 10, ...
  2228.         aPopupRec.fLastChoice    = 3 + (thePrefs.boundSlabThreshold / 5);
  2229.     else
  2230.         aPopupRec.fLastChoice    = 1; // off
  2231.     AddPopupToList(&aPopupRec);
  2232.  
  2233.     // Add the Max Symbols popup
  2234.     aPopupRec.fParentDialog    = myDialog;
  2235.     aPopupRec.fMenuID        = kMenuID_fMaxSym;
  2236.     aPopupRec.fPopupItemID    = kPU_fMaxSyms;
  2237.     if (thePrefs.maxSymbolsVal < kMaxSymMinVal)
  2238.         thePrefs.maxSymbolsVal = kMaxSymMinVal;
  2239.     else if (thePrefs.maxSymbolsVal > kMaxSymMaxVal)
  2240.         thePrefs.maxSymbolsVal = kMaxSymMaxVal;
  2241.     // set fLastChoice to 1, 2, 3, etc.
  2242.     aPopupRec.fLastChoice    = (thePrefs.maxSymbolsVal / kMaxSymFactor);
  2243.     AddPopupToList(&aPopupRec);
  2244.  
  2245.     // Add the Language Version popup
  2246.     aPopupRec.fParentDialog    = myDialog;
  2247.     aPopupRec.fMenuID        = kMenuID_fLangVersion;
  2248.     aPopupRec.fPopupItemID    = kPU_fLangVersion;
  2249.     if (thePrefs.languageVersion < kMinLangVersion)
  2250.         thePrefs.languageVersion = kMinLangVersion;
  2251.     else if (thePrefs.languageVersion > kMaxLangVersion)
  2252.         thePrefs.languageVersion = kMaxLangVersion;
  2253.     aPopupRec.fLastChoice    = thePrefs.languageVersion;
  2254.     AddPopupToList(&aPopupRec);
  2255.  
  2256.     // Add the Progress popup
  2257.     aPopupRec.fParentDialog    = myDialog;
  2258.     aPopupRec.fMenuID        = kMenuID_fProgress;
  2259.     aPopupRec.fPopupItemID    = kPU_fProgress;
  2260.     if (thePrefs.progress < kProgNone)
  2261.         thePrefs.progress = kProgNone;
  2262.     else if (thePrefs.progress > kProgMax)
  2263.         thePrefs.progress = kProgMax;
  2264.  
  2265.     // set fLastChoice to 1, 2, 3, etc.
  2266.     aPopupRec.fLastChoice    = thePrefs.progress;
  2267.     AddPopupToList(&aPopupRec);
  2268.  
  2269.     sprintf(s1, "%d", thePrefs.imageWidth);
  2270.     SetIText((Handle) cntl[kET_fImageWidth], c2pstr(s1) );
  2271.  
  2272.     sprintf(s1, "%d", thePrefs.imageHeight);
  2273.     SetIText((Handle) cntl[kET_fImageHeight], c2pstr(s1) );
  2274.  
  2275.     sprintf(s1, "%d", thePrefs.selectionArea.top);
  2276.     SetIText((Handle) cntl[kET_fRowFrom], c2pstr(s1) );
  2277.  
  2278.     sprintf(s1, "%d", thePrefs.selectionArea.bottom);
  2279.     SetIText((Handle) cntl[kET_fRowTo], c2pstr(s1) );
  2280.  
  2281.     // Currently, selection L/R is not settable, so force its value
  2282.     thePrefs.selectionArea.left = 1;
  2283.     thePrefs.selectionArea.right = thePrefs.imageWidth;
  2284.  
  2285.     SetCtlValue(cntl[kCB_fAntiAliasCheck], thePrefs.doAntialias);
  2286.  
  2287.     sprintf(s1, "%.2f", thePrefs.antialiasThreshold);
  2288.     SetIText((Handle) cntl[kET_fAntiAliasThresh], c2pstr(s1) );
  2289.  
  2290.     sprintf(s1, "%d", thePrefs.antialiasDepth);
  2291.     SetIText((Handle) cntl[kST_fAntialiasDepth], c2pstr(s1) );
  2292.  
  2293.     sprintf(s1, "%.2f", thePrefs.antiJitterScale);
  2294.     SetIText((Handle) cntl[kET_fAntiJitterScale], c2pstr(s1) );
  2295.  
  2296.     SetCtlValue(cntl[kCB_fAnimate], thePrefs.doAnimation);
  2297.     HiliteControl(cntl[kBT_fAnimSettings], thePrefs.doAnimation?0:255);  // dimmed
  2298.  
  2299.     SetCtlValue(cntl[kCB_fDoPICTCmp], (thePrefs.doCompression && gHasImageCompressionMgr));
  2300.     HiliteControl(cntl[kCB_fDoPICTCmp], gHasImageCompressionMgr?0:255);  // dimmed
  2301.     HiliteControl(cntl[kBT_fPICTCmpSettings], GetCtlValue(cntl[kCB_fDoPICTCmp])?0:255);    // enabled
  2302.  
  2303.     SetCtlValue(cntl[kCB_fCreateTarga], thePrefs.createTargaOutfile);
  2304.     if(thePrefs.createTargaOutfile)
  2305.         SetCtlValue(cntl[kCB_fContinueFromTarga], thePrefs.continueTarga);
  2306.     else
  2307.         HiliteControl(cntl[kCB_fContinueFromTarga], 255);
  2308.  
  2309.     // Save as default always starts out as OFF
  2310.     SetCtlValue(cntl[kCB_SaveAsDefault], false);
  2311.  
  2312.     // select something...
  2313.     SelIText(myDialog, kET_fImageWidth, 0, -1);
  2314.  
  2315.     PositionWindow(myDialog, ewcDoCentering, eSameAsPassedWindow, (WindowPtr)gp2wWindow);
  2316.  
  2317.     // "default" the OK button
  2318.     SetupDefaultButton(myDialog);
  2319.     SetCursor(&qd.arrow);
  2320.     ShowWindow(myDialog);
  2321.     update_edit_text(myDialog);
  2322.  
  2323.     do
  2324.     {
  2325. #if defined(__powerc)
  2326.         ModalDialog((ModalFilterUPP)&gModalFilterRD, &itemHit);
  2327. #else
  2328.         ModalDialog((ModalFilterProcPtr)ModalFilter, &itemHit);
  2329. #endif
  2330.         switch (itemHit)
  2331.         {
  2332.             case kCB_fAntiAliasCheck:        /* anti-alias */
  2333.                 SetCtlValue(cntl[itemHit], !GetCtlValue(cntl[itemHit]));
  2334.                 update_edit_text(myDialog);
  2335.                   break;
  2336.  
  2337.             case kCB_fCreateTarga:  /* Create Targa file */
  2338.                 SetCtlValue(cntl[itemHit], !GetCtlValue(cntl[itemHit]));
  2339.                 if (GetCtlValue(cntl[itemHit]) == 0)
  2340.                 {
  2341.                     // if no Targa output, then certainly no contine
  2342.                     SetCtlValue(cntl[kCB_fContinueFromTarga],0);
  2343.                     HiliteControl(cntl[kCB_fContinueFromTarga], 255); // dim it
  2344.                 }
  2345.                 else
  2346.                     HiliteControl(cntl[kCB_fContinueFromTarga], 0);
  2347.                 break;
  2348.  
  2349.             case kCB_fContinueFromTarga:
  2350.             case kCB_SaveAsDefault:
  2351.                 SetCtlValue(cntl[itemHit], !GetCtlValue(cntl[itemHit]));
  2352.                 break;
  2353.  
  2354.             case kCB_fDoPICTCmp:
  2355.                 SetCtlValue(cntl[itemHit], !GetCtlValue(cntl[itemHit]));
  2356.                 HiliteControl(cntl[kBT_fPICTCmpSettings],
  2357.                             GetCtlValue(cntl[kCB_fDoPICTCmp])?0:255);
  2358.                 break;
  2359.  
  2360.             case kBT_fPICTCmpSettings:
  2361.                 {
  2362.                 (void)SCRequestImageSettings(gtheSCComponent);
  2363.                 break;
  2364.                 }
  2365.  
  2366.             case kCB_fAnimate:
  2367.                 SetCtlValue(cntl[itemHit], !GetCtlValue(cntl[itemHit]));
  2368.                 HiliteControl(cntl[kBT_fAnimSettings],
  2369.                             GetCtlValue(cntl[itemHit])?0:255);
  2370.                 break;
  2371.  
  2372.             case kBT_fAnimSettings:
  2373.                 GetAnimateOptions(&thePrefs.animRec);
  2374.                 break;
  2375.  
  2376.             case kPU_fImageSize:
  2377.                 // get index into imageSize array
  2378.                 i = GetPopupValue(kPU_fImageSize) - 1;
  2379.  
  2380.                 // width
  2381.                 sprintf(s1, "%d", scrnSizeMenu[i][0]);    // X (width)
  2382.                 c2pstr(s1);
  2383.                 SetIText((Handle) cntl[kET_fImageWidth], (StringPtr)s1);
  2384.  
  2385.                 // height
  2386.                 sprintf(s1, "%d", scrnSizeMenu[i][1]); // Y (height)
  2387.                 c2pstr(s1);
  2388.                 SetIText((Handle) cntl[kET_fImageHeight], (StringPtr)s1);
  2389.  
  2390.                 // from top (always 1)
  2391.                 SetIText((Handle) cntl[kET_fRowFrom], "\p1");
  2392.                 // to bottom
  2393.                 SetIText((Handle) cntl[kET_fRowTo], (StringPtr)s1);
  2394.  
  2395.                 // Currently, selection L/R is not settable, so force its value
  2396.                 thePrefs.selectionArea.left = 1;
  2397.                 thePrefs.selectionArea.right = scrnSizeMenu[i][0];    // X (width)
  2398.  
  2399.                 // re-select first item (size may have changed)
  2400.                 SelIText(myDialog, kET_fImageWidth, 0, -1);
  2401.                 break;
  2402.         }
  2403.     }
  2404.     while (itemHit != ok && itemHit != cancel);
  2405.     
  2406.     if (itemHit == ok)
  2407.     {
  2408.         GetIText((Handle) cntl[kET_fImageWidth], (StringPtr)s1);
  2409.         sscanf(p2cstr((StringPtr)s1) , "%hd", &thePrefs.imageWidth);
  2410.         PinValue(&thePrefs.imageWidth, 1, 9999);
  2411.         thePrefs.selectionArea.right = thePrefs.imageWidth;
  2412.  
  2413.         GetIText((Handle) cntl[kET_fImageHeight], (StringPtr)s1);
  2414.         sscanf(p2cstr((StringPtr)s1) , "%hd", &thePrefs.imageHeight);
  2415.         PinValue(&thePrefs.imageHeight, 1, 9999);
  2416.  
  2417.         GetIText((Handle) cntl[kET_fRowFrom], (StringPtr)s1);
  2418.         sscanf(p2cstr((StringPtr)s1) , "%hd", &thePrefs.selectionArea.top);
  2419.         PinValue(&thePrefs.selectionArea.top, 1, thePrefs.imageHeight);
  2420.  
  2421.         GetIText((Handle) cntl[kET_fRowTo], (StringPtr)s1);
  2422.         sscanf(p2cstr((StringPtr)s1) , "%hd", &thePrefs.selectionArea.bottom);
  2423.         PinValue(&thePrefs.selectionArea.bottom, thePrefs.selectionArea.top, thePrefs.imageHeight);
  2424.  
  2425.         thePrefs.renderQuality = GetPopupValue(kPU_fImageQuality)-1;
  2426.  
  2427.         thePrefs.doAntialias = GetCtlValue(cntl[kCB_fAntiAliasCheck]);
  2428.  
  2429.         GetIText((Handle) cntl[kET_fAntiAliasThresh], (StringPtr)s1);
  2430.         sscanf(p2cstr((StringPtr)s1) , "%f", &thePrefs.antialiasThreshold);
  2431.         if (thePrefs.antialiasThreshold > 2.0)
  2432.             thePrefs.antialiasThreshold = 2.0;
  2433.         else if (thePrefs.antialiasThreshold < 0.0)
  2434.             thePrefs.antialiasThreshold = 0.0;
  2435.  
  2436.         GetIText((Handle) cntl[kST_fAntialiasDepth], (StringPtr)s1);
  2437.         thePrefs.antialiasDepth = atoi(p2cstr((StringPtr)s1));
  2438.         PinValue(&thePrefs.antialiasDepth, 1, 9);
  2439.  
  2440.         GetIText((Handle) cntl[kET_fAntiJitterScale], (StringPtr)s1);
  2441.         thePrefs.antiJitterScale = atof(p2cstr((StringPtr)s1));
  2442.         if (thePrefs.antiJitterScale > 2.0)
  2443.             thePrefs.antiJitterScale = 2.0;
  2444.         else if (thePrefs.antiJitterScale < 0.0)
  2445.             thePrefs.antiJitterScale = 0.0;
  2446.  
  2447.         thePrefs.progress = GetPopupValue(kPU_fProgress);
  2448.  
  2449.         // off, ---, 1, 5, 10, 15, ...
  2450.         thePrefs.boundSlabThreshold = (GetPopupValue(kPU_fMaxBounds)-3)*5;
  2451.         // if popup was at position 1,2, set to 0...
  2452.         if (thePrefs.boundSlabThreshold < 0)
  2453.             thePrefs.boundSlabThreshold = 0;
  2454.         else // if at 3, set the value to 1
  2455.         if (thePrefs.boundSlabThreshold == 0)
  2456.             thePrefs.boundSlabThreshold = 1;
  2457.  
  2458.         // if popup is not at position 1 (off) then it must be on! :-)
  2459.         thePrefs.doBoundSlabs = (GetPopupValue(kPU_fMaxBounds) > 1);
  2460.  
  2461.         thePrefs.doAnimation = GetCtlValue(cntl[kCB_fAnimate]);
  2462.  
  2463.         thePrefs.languageVersion =  GetPopupValue(kPU_fLangVersion);
  2464.  
  2465.         thePrefs.doCompression = GetCtlValue(cntl[kCB_fDoPICTCmp]);
  2466.         if (thePrefs.doCompression)
  2467.             (void)SCGetInfo(gtheSCComponent, scSpatialSettingsType, &(**gDefltFilePrefs_h).sc_DialogParams);
  2468.  
  2469.         thePrefs.maxSymbolsVal = kMaxSymMinVal +
  2470.                 ((GetPopupValue(kPU_fMaxSyms)-1) * kMaxSymFactor);
  2471.  
  2472.         thePrefs.createTargaOutfile = GetCtlValue(cntl[kCB_fCreateTarga]);
  2473.         thePrefs.continueTarga = GetCtlValue(cntl[kCB_fContinueFromTarga]);
  2474.  
  2475.         // make sure from/to width is in range
  2476.         if    (
  2477.                 (thePrefs.selectionArea.left > 1)
  2478.             ||    (thePrefs.selectionArea.top > 1)
  2479.             ||    (thePrefs.selectionArea.right < thePrefs.imageWidth)
  2480.             ||    (thePrefs.selectionArea.bottom < thePrefs.imageHeight)
  2481.             )
  2482.         {
  2483.             // you picked sub-area to render, OK?
  2484.             itemHit = displayDialog(146, NULL, 0, ewcDoCentering, eSameAsPassedWindow);
  2485.             if (itemHit == cancel)
  2486.             {
  2487.                 // they changed their mind, restore sanity
  2488.                 thePrefs.selectionArea.left = 1;
  2489.                 thePrefs.selectionArea.top = 1;
  2490.                 thePrefs.selectionArea.right = thePrefs.imageWidth;
  2491.                 thePrefs.selectionArea.bottom = thePrefs.imageHeight;
  2492.             }
  2493.         }
  2494.  
  2495.         // Set default file prefs to mirror current file prefs settings?
  2496.         if (GetCtlValue(cntl[kCB_SaveAsDefault]))
  2497.             **gDefltFilePrefs_h = thePrefs;
  2498.  
  2499.         // fill in the prefs with new values
  2500.         **gFilePrefs_h = thePrefs;
  2501.  
  2502.         // save prefs in file if OK
  2503.         WriteFilePrefs();
  2504.     }
  2505.  
  2506.     // all done with the popup menus
  2507.     KillPopups();
  2508.  
  2509.     SetCursor(&qd.arrow);
  2510.  
  2511.     // get rid of the dialog
  2512.     DisposeDialog(myDialog);
  2513.  
  2514.     EnableMenus();
  2515. } // ChangeFilePrefs
  2516.  
  2517.  
  2518.  
  2519. // ---------------------------------------------------------------------
  2520. // set up the POV-Ray engine's argc/argv parameters from file settings
  2521. static void SetupRenderArgs(void)
  2522. {
  2523.     int        i;
  2524.     char    s1[256], s2[256];
  2525.  
  2526.     ResetArgs();
  2527.  
  2528.     AddArg("POV-Ray"); // argv[0] is always the program name
  2529.  
  2530.     // display format (just used to turn on the display calls)
  2531.     AddArg("+d0");
  2532.  
  2533.     // Min Language Syntax Version
  2534.     AddArg((**gPrefs2Use_h).languageVersion==1 ? "+mv1" : "+mv2");
  2535.  
  2536.     // renderQuality value
  2537.     sprintf(s1, "-q%d", (**gPrefs2Use_h).renderQuality);
  2538.     AddArg(s1);
  2539.  
  2540.     // file buffer size in Kbytes
  2541.     AddArg("+b8");
  2542.  
  2543.     // prompt for keypress on exit (In the Mac world?  NOT!)
  2544.     AddArg("-p");
  2545.  
  2546.     // set clock variable value
  2547.     if ((**gPrefs2Use_h).doAnimation)
  2548.         sprintf(s2, "%g", GetCurrClockVal());
  2549.     else
  2550.         sprintf(s2, "%g", 0.0);
  2551.     sprintf(s1, "+k%s",s2);
  2552.     AddArg(s1);
  2553.  
  2554.     // set max symbols value
  2555.     sprintf(s1, "+ms%d", (**gPrefs2Use_h).maxSymbolsVal);
  2556.     AddArg(s1);
  2557.  
  2558.     // show render progress messages
  2559.     switch ((**gPrefs2Use_h).progress)
  2560.     {
  2561.         case kProgDebug:
  2562.             AddArg("+z");
  2563.             // fall through & get the +v1 too
  2564.  
  2565.         case kProgVerbose:
  2566.             AddArg("+v1");
  2567.             break;
  2568.  
  2569.         case kProgNone:
  2570.         case kProgMinimal:
  2571.             // Minimal is Mac debugs, not core debugs
  2572.             AddArg("-v");
  2573.             break;
  2574.     }
  2575.  
  2576.     // exit enable (Not needed on Mac, exit via COOPERATE)
  2577.     AddArg("-x");
  2578.  
  2579.     // render output size
  2580.     sprintf(s1, "-w%d", (**gPrefs2Use_h).imageWidth); AddArg(s1);
  2581.     sprintf(s1, "-h%d", (**gPrefs2Use_h).imageHeight); AddArg(s1);
  2582.  
  2583.     // actual render rectangle
  2584.     sprintf(s1, "-sr%d", (**gPrefs2Use_h).selectionArea.top); AddArg(s1);
  2585.     sprintf(s1, "-er%d", (**gPrefs2Use_h).selectionArea.bottom); AddArg(s1);
  2586.     sprintf(s1, "-sc%d", (**gPrefs2Use_h).selectionArea.left); AddArg(s1);
  2587.     sprintf(s1, "-ec%d", (**gPrefs2Use_h).selectionArea.right); AddArg(s1);
  2588.  
  2589.     // enable/disable bounding slabs
  2590.     if ((**gPrefs2Use_h).doBoundSlabs)
  2591.     {
  2592.         // set min objects to start auto-bounding
  2593.         sprintf(s2, "%d", (**gPrefs2Use_h).boundSlabThreshold);
  2594.         sprintf(s1, "+mb%s",s2);
  2595.         AddArg(s1);
  2596.     }
  2597.     else
  2598.         AddArg("-mb");
  2599.  
  2600.     // anti-aliasing
  2601.     if ((**gPrefs2Use_h).doAntialias)
  2602.     {
  2603.         sprintf(s1, "+a%g", (**gPrefs2Use_h).antialiasThreshold);
  2604.         AddArg(s1);
  2605.  
  2606.         // Anti-aliasing Depth
  2607.         sprintf(s1, "+r%d", (**gPrefs2Use_h).antialiasDepth);
  2608.         AddArg(s1);
  2609.  
  2610.         // Anti-aliasing Jitter Scale
  2611.         if ((**gPrefs2Use_h).antiJitterScale > 0.0)
  2612.         {
  2613.             sprintf(s1, "+j%g", (**gPrefs2Use_h).antiJitterScale);
  2614.             AddArg(s1);
  2615.         }
  2616.         else
  2617.             AddArg("-j");
  2618.     }
  2619.     else
  2620.         AddArg("-a");
  2621.  
  2622.     // output targa file
  2623.     AddArg((**gPrefs2Use_h).createTargaOutfile ? "+ft" : "-f");
  2624.  
  2625.     // continue with previous targa file
  2626.     AddArg((**gPrefs2Use_h).continueTarga ? "+c" : "-c");
  2627.  
  2628.     // input file
  2629.     pStrCopy(gSrcWind_FileName, (StringPtr)s2);
  2630.     p2cstr((StringPtr)s2);
  2631.     sprintf(s1, "-i%s", s2); AddArg(s1);
  2632.     
  2633.     // set up targa output file name
  2634.     if ((**gPrefs2Use_h).createTargaOutfile)
  2635.     {
  2636.         // whack .POV suffix off input file name
  2637.         if ( strstr(s2, ".POV") || strstr(s2, ".pov") )
  2638.         {
  2639.             i = strlen(s2);
  2640.             s2[i - 4] = 0;
  2641.         }
  2642.  
  2643.         // add .tga suffix
  2644.         strcat(s2, ".tga");
  2645.         strcpy(gTargaFname, s2);
  2646.         sprintf(s1, "-o%s", s2);
  2647.         AddArg(s1);
  2648.     }
  2649.  
  2650.     // Add -l options for library paths
  2651.     // convert volume name to vref for making full path
  2652.     VolName2VRef((**gAppPrefs_h).includeDirFSSpec.name,
  2653.                 &(**gAppPrefs_h).includeDirFSSpec.vRefNum);
  2654.     PathNameFromDirID((**gAppPrefs_h).includeDirFSSpec.parID, (**gAppPrefs_h).includeDirFSSpec.vRefNum, s2);
  2655.     // whack trailing colon, POV-Ray wants to add it!
  2656.     if (s2[strlen(s2)-1] == ':')
  2657.         s2[strlen(s2)-1] = '\0';
  2658.     sprintf(s1, "-l%s", s2);
  2659.     AddArg(s1);
  2660.     
  2661.     // set current directory to that of scene file
  2662.     SetVol(NULL, gSrcWind_VRefNum);
  2663.  
  2664.     // flush any pending writes prior to rendering
  2665.     FlushVol(NULL, gSrcWind_VRefNum);
  2666.  
  2667.     Stop_Flag = 0;
  2668.     gDoingRender = true;
  2669.  
  2670.     // calculate and display current CPU timeslice setting
  2671.     CalcCpuReleaseTicks(true);
  2672.  
  2673. } // SetupRenderArgs
  2674.  
  2675.  
  2676.  
  2677. // ---------------------------------------------------------------------
  2678. // Display Application About Box
  2679. static void AboutPOV(void)
  2680. {
  2681.     short        itemHit;
  2682.     Boolean        specialAbout = false;
  2683.     DialogPtr    myDialog;
  2684.     char        povVers[16],
  2685.                 compilerName[16],
  2686.                 compDate[32];
  2687.  
  2688.     // grab the dialog into memory
  2689.     myDialog = GetNewDialog(130, NULL, (WindowPtr) -1);
  2690.     if (myDialog)
  2691.     {
  2692.         // check for special info-key for about box
  2693.         if (gTheEvent.modifiers & optionKey)
  2694.         {
  2695.             specialAbout = false;
  2696.             PlayNotifySound();
  2697.         }
  2698.  
  2699.         strcpy(compDate, "Compiled: ");
  2700.         strcat(compDate, __DATE__);
  2701.         c2pstr(compDate);
  2702.  
  2703.         strcpy(povVers, POV_RAY_VERSION);
  2704.         c2pstr(povVers);
  2705.  
  2706.         strcpy(compilerName, COMPILER_VER);
  2707.         c2pstr(compilerName);
  2708.  
  2709.         GetAppVersionPString(1, (StringPtr)povVers);
  2710.  
  2711.         ParamText(    (StringPtr)povVers,
  2712.                     (StringPtr)compilerName,
  2713.                     (StringPtr)compDate,
  2714.                     (StringPtr)gDistMessage);
  2715.  
  2716.         /* Get into dialog's port & fiddle with fonts.. */
  2717.         SetPort((GrafPtr)myDialog);
  2718.         TextFont(geneva);
  2719.         TextSize(9);
  2720.  
  2721.         PositionWindow(myDialog, ewcDoCentering, eDeepestDevice, (WindowPtr)gp2wWindow);
  2722.  
  2723.         /* "default" the OK button */
  2724.         SetupDefaultButton(myDialog);
  2725.         ShowWindow(myDialog);
  2726.         do {
  2727.             ModalDialog(NULL, &itemHit);
  2728.             // make noise if other stuff clicked.. just for fun
  2729.             if (itemHit != 1)
  2730.                 PlayNotifySound();
  2731.         } while (itemHit != 1);
  2732.         TextFont(geneva);
  2733.         TextSize(9);
  2734.         DisposeDialog(myDialog);
  2735.     }
  2736.  
  2737. } // AboutPOV
  2738.  
  2739.  
  2740.  
  2741. // ---------------------------------------------------------------------
  2742. // Set all menu items availability depending on application states
  2743. static void SetItemEnable(MenuHandle theMenu, short theItem, Boolean isEnabled)
  2744. {
  2745.     if (isEnabled)
  2746.         EnableItem(theMenu, theItem);
  2747.     else
  2748.         DisableItem(theMenu, theItem);
  2749. } // SetItemEnable
  2750.  
  2751.  
  2752.  
  2753. // ---------------------------------------------------------------------
  2754. // Set all menu items availability depending on application states
  2755. static void AdjustMenus(void)
  2756. {
  2757.     short        i;
  2758.     WindowPtr    theFrontWindow;
  2759.  
  2760.     // Find out which window is in front, many menus depend on which is frontmost.
  2761.     theFrontWindow = FrontWindow();
  2762.  
  2763.  
  2764.     //======== APPLE
  2765.  
  2766.     SetItemEnable(myMenus[apmn_ID - menu_offset], apmn_about, true); /* about box */
  2767.  
  2768.  
  2769.     //======== FILE
  2770.  
  2771.     // New
  2772.     SetItemEnable(myMenus[fmn_ID - menu_offset], fmn_new, !gDoingRender && !gSrcWind_dirty);
  2773.  
  2774.     // Open
  2775.     SetItemEnable(myMenus[fmn_ID - menu_offset], fmn_open, !gDoingRender && !gSrcWind_dirty);
  2776.  
  2777.     // Close
  2778.     SetItemEnable(myMenus[fmn_ID - menu_offset], fmn_close, false);
  2779.     if (theFrontWindow == gSrcWind_Window)
  2780.     {
  2781.         if (!gDoingRender)
  2782.             SetItemEnable(myMenus[fmn_ID - menu_offset], fmn_close, true);
  2783.         }
  2784. /* -- not yet, need to prompt to save first
  2785.     else if (theFrontWindow == gImageWindowPtr)
  2786.     {
  2787.         SetItemEnable(myMenus[fmn_ID - menu_offset], fmn_close, true);
  2788.     }
  2789. */
  2790.  
  2791.     // Save
  2792.     if (theFrontWindow == gSrcWind_Window)
  2793.     {
  2794.         SetItemEnable(myMenus[fmn_ID - menu_offset], fmn_save, gSrcWind_dirty || (gSrcWind_VRefNum == 0));
  2795.     }
  2796.     else if (theFrontWindow == (WindowPtr)gp2wWindow)
  2797.     {
  2798.         SetItemEnable(myMenus[fmn_ID - menu_offset], fmn_save, true);
  2799.     }
  2800.     else if (theFrontWindow == gImageWindowPtr)
  2801.     {
  2802.         SetItemEnable(myMenus[fmn_ID - menu_offset], fmn_save, !gDoingRender);
  2803.     }
  2804.  
  2805.     // Save As
  2806.     if (theFrontWindow == gSrcWind_Window)
  2807.     {
  2808.         SetItemEnable(myMenus[fmn_ID - menu_offset], fmn_saveas, true);
  2809.     }
  2810.     else if (theFrontWindow == gImageWindowPtr)
  2811.     {
  2812.         SetItemEnable(myMenus[fmn_ID - menu_offset], fmn_saveas, !gDoingRender);
  2813.     }
  2814.     else
  2815.     {
  2816.         SetItemEnable(myMenus[fmn_ID - menu_offset], fmn_saveas, false);
  2817.     }
  2818.  
  2819.  
  2820.     //======== EDIT
  2821.  
  2822.     // undo
  2823.     SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_undo,
  2824.             ( (theFrontWindow == gSrcWind_Window) && (undo_record[max_undo].reason[0]) )
  2825.             || ( (theFrontWindow == gImageWindowPtr) && gCanUndo) );
  2826.  
  2827.     // cut
  2828.     if (theFrontWindow == gSrcWind_Window)
  2829.     {
  2830.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_cut,
  2831.                 (**gSrcWind_TEH).selStart != (**gSrcWind_TEH).selEnd);
  2832.     }
  2833.     else
  2834.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_cut, false);
  2835.  
  2836.     // copy
  2837.     if (theFrontWindow == gSrcWind_Window)
  2838.     {
  2839.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_copy,
  2840.                 (**gSrcWind_TEH).selStart != (**gSrcWind_TEH).selEnd);
  2841.     }
  2842.     else
  2843.     if (theFrontWindow == gImageWindowPtr)
  2844.     {
  2845.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_copy, true);
  2846.     }
  2847.     else
  2848.     if (theFrontWindow == (WindowPtr)gp2wWindow)
  2849.     {
  2850.         SetItemEnable(myMenus[edmn_ID - menu_offset],
  2851.             edmn_copy,
  2852.             (**(gp2wWindow->p2wTEHandle)).selStart !=
  2853.             (**(gp2wWindow->p2wTEHandle)).selEnd );
  2854.     }
  2855.  
  2856.     // paste
  2857.     if (theFrontWindow == gSrcWind_Window)
  2858.     { // can only paste into src window
  2859.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_paste, true);
  2860.     }
  2861.     else
  2862.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_paste, false);
  2863.  
  2864.     // clear
  2865.     if (theFrontWindow == gSrcWind_Window)
  2866.     {
  2867.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_clear,
  2868.                 (**gSrcWind_TEH).selStart != (**gSrcWind_TEH).selEnd);
  2869.     }
  2870.     else
  2871.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_clear, false);
  2872.  
  2873.  
  2874.     // select all
  2875.     if ((theFrontWindow == gSrcWind_Window) || (theFrontWindow == (WindowPtr)gp2wWindow))
  2876.     {
  2877.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_selectAll, true);
  2878.     }
  2879.     else
  2880.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_selectAll, false);
  2881.  
  2882.     // redo
  2883.     if (theFrontWindow == gSrcWind_Window)
  2884.     {
  2885.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_redo, redo_record[max_undo].reason[0]);
  2886.     }
  2887.     else
  2888.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_redo, false);
  2889.  
  2890.     // goto
  2891.     SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_goto, gSrcWind_visible);
  2892.  
  2893.     // lookup
  2894.     if (theFrontWindow == gSrcWind_Window)
  2895.     {
  2896.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_lookup,
  2897.                 (**gSrcWind_TEH).selStart != (**gSrcWind_TEH).selEnd);
  2898.     }
  2899.     else
  2900.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_lookup, false);
  2901.  
  2902.     // insert template
  2903.     SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_macros, gSrcWind_visible);
  2904.  
  2905.  
  2906.     //======== IMAGE
  2907.  
  2908.     // view
  2909.     SetItemEnable(myMenus[immn_ID - menu_offset], immn_view, true);
  2910.         // should disable view submenu if !gSrcWind_visible...
  2911.  
  2912.     // dither
  2913.     SetItemEnable(myMenus[immn_ID - menu_offset], immn_dither, gHas32BitQD);
  2914.     CheckItem(myMenus[immn_ID - menu_offset], immn_dither, ((**gPrefs2Use_h).doDither && gHas32BitQD));
  2915.  
  2916.     // custom palette
  2917.     SetItemEnable(myMenus[immn_ID - menu_offset], immn_custom, true);
  2918.  
  2919.  
  2920.     //======== RENDER
  2921.  
  2922.     // Render options
  2923.     SetItemEnable(myMenus[rnmn_ID - menu_offset], rnmn_options,
  2924.                 !gDoingRender && (gSrcWind_VRefNum != 0));
  2925.  
  2926.     // render
  2927.     SetItemEnable(myMenus[rnmn_ID - menu_offset], rnmn_render,
  2928.                 !gDoingRender && (gSrcWind_VRefNum != 0));
  2929.  
  2930.     // pause rendering
  2931.     SetItemEnable(myMenus[rnmn_ID - menu_offset], rnmn_pause, gDoingRender);
  2932.  
  2933.     // stop rendering
  2934.     SetItemEnable(myMenus[rnmn_ID - menu_offset], rnmn_stop, gDoingRender);
  2935.  
  2936.     // auto-save & auto-shutdown
  2937.     CheckItem(myMenus[rnmn_ID - menu_offset], rnmn_autosave, gAutoSave);
  2938.     CheckItem(myMenus[rnmn_ID - menu_offset], rnmn_shutdown, gAutoShutdown);
  2939.  
  2940.  
  2941.     //======== PROCESSING
  2942.  
  2943.     for (i=psmn_border; i <= psmn_revert; i++)
  2944.     {
  2945.         Boolean b;
  2946.         b =    !gDoingRender
  2947.             && (theFrontWindow == gImageWindowPtr)
  2948.             && ((WindowPeek)gImageWindowPtr)->visible
  2949.             && !gDoingVirtualFile;
  2950.         if (i != psmn_divider1)
  2951.             SetItemEnable(myMenus[psmn_ID - menu_offset], i, b);
  2952.     }
  2953.  
  2954.  
  2955.     //======== WINDOWS
  2956.  
  2957.     // [1] status window
  2958.     CheckItem(myMenus[wndmn_ID - menu_offset], wndmn_status, theFrontWindow == (WindowPtr)gp2wWindow);
  2959.     SetItemEnable(myMenus[wndmn_ID - menu_offset], wndmn_status, gp2wWindow != NULL);
  2960.  
  2961.     // [2] source window
  2962.     CheckItem(myMenus[wndmn_ID - menu_offset], wndmn_source, theFrontWindow == gSrcWind_Window);
  2963.     SetItemEnable(myMenus[wndmn_ID - menu_offset], wndmn_source, gSrcWind_visible);
  2964.  
  2965.     // [3] image window
  2966.     CheckItem(myMenus[wndmn_ID - menu_offset], wndmn_image, theFrontWindow == gImageWindowPtr);
  2967.     SetItemEnable(myMenus[wndmn_ID - menu_offset], wndmn_image, gImageWindowPtr && ((WindowPeek)gImageWindowPtr)->visible);
  2968.  
  2969.  
  2970.     //======== VIEW SUBMENU
  2971.  
  2972.     SetItemEnable(mySubMenus[viewmn_ID - submenu_offset], 0, true);
  2973.     for (i=viewmn_hidden; i <= viewmn_x4; i++)
  2974.         CheckItem(mySubMenus[viewmn_ID - submenu_offset], i, i == (**gPrefs2Use_h).imageMagFactor);
  2975.  
  2976.  
  2977.     //======== CUSTOM PALETTE SUBMENU
  2978.  
  2979.     SetItemEnable(mySubMenus[plmn_ID - submenu_offset], 0, gHasPictUtils);
  2980.     CheckItem(mySubMenus[plmn_ID - submenu_offset], palette_none, !use_custom_palette);
  2981.     CheckItem(mySubMenus[plmn_ID - submenu_offset], palette_default, gColorQuantMethod == systemMethod);
  2982.     CheckItem(mySubMenus[plmn_ID - submenu_offset], palette_median, gColorQuantMethod == medianMethod);
  2983.     CheckItem(mySubMenus[plmn_ID - submenu_offset], palette_popular, gColorQuantMethod == popularMethod);
  2984.  
  2985. } // AdjustMenus
  2986.  
  2987.  
  2988.  
  2989. // ---------------------------------------------------------------------
  2990. // Prompt user "OK to Quit?"
  2991. static void ask_about_quit(void)
  2992. {
  2993.     short        itemHit;
  2994.  
  2995.     if    (gDoingRender && ((**gPrefs2Use_h).createTargaOutfile == 0))
  2996.     {
  2997.         // ok to quit?
  2998.         itemHit = displayDialog(137, NULL, 0, ewcDoCentering, eSameAsPassedWindow);
  2999.         if (itemHit == ok)
  3000.             Stop_Flag = gQuit = 1;
  3001.     }
  3002.     else
  3003.         Stop_Flag = gQuit = 1;
  3004. } // ask_about_quit
  3005.  
  3006.  
  3007.  
  3008. // ---------------------------------------------------------------------
  3009. // Prompt user, "OK to Stop Rendering?"
  3010. static void ask_about_stop(void)
  3011. {
  3012.     short        itemHit;
  3013.  
  3014.     if    ((**gPrefs2Use_h).createTargaOutfile)
  3015.         // stopped, to continue, use targa..
  3016.         itemHit = displayDialog(135, NULL, 0, ewcDoCentering, eSameAsPassedWindow);
  3017.     else
  3018.         // no targa, OK to stop?
  3019.         itemHit = displayDialog(134, NULL, 0, ewcDoCentering, eSameAsPassedWindow);
  3020.  
  3021.     if (itemHit == ok)
  3022.     {
  3023.         Stop_Flag = 1;
  3024.         HaltFileQ(); // halt any queued files too!
  3025.     }
  3026. } // ask_about_stop
  3027.  
  3028.  
  3029.  
  3030. // ---------------------------------------------------------------------
  3031. // Pause rendering until user continues
  3032. static void pause_it(void)
  3033. {
  3034.  
  3035.     if (gPaused == 1)
  3036.         gPaused = 2;    // already recursively paused, so now un-pause
  3037.     else
  3038.     {    // prepare to pause
  3039.         gPaused = 1;
  3040.         DisableMenus();
  3041.  
  3042.         // re-enable just the pause menu item
  3043.         EnableItem(myMenus[rnmn_ID - menu_offset], 0);
  3044.         EnableItem(myMenus[rnmn_ID - menu_offset], rnmn_pause);
  3045.         CheckItem(myMenus[rnmn_ID - menu_offset], rnmn_pause, 1);
  3046.         DrawMenuBar();
  3047.  
  3048.         // pause loop..
  3049.         do
  3050.         {
  3051.             // allow user to do stuff..
  3052.             Cooperate(true);
  3053.             // until they pick pause again (2)
  3054.         } while ((Stop_Flag == 0) && (gPaused != 2));
  3055.     
  3056.         // done pausing, restore & return
  3057.         EnableMenus();
  3058.         CheckItem(myMenus[rnmn_ID - menu_offset], rnmn_pause, 0);
  3059.         gPaused = 0;
  3060.     }
  3061. } // pause_it
  3062.  
  3063.  
  3064.  
  3065. // ---------------------------------------------------------------------
  3066. // Handle any window's Activate event
  3067. static void HandleActivate(WindowPtr theWindow, Boolean becomingActive)
  3068. {
  3069. /* Show/hide the window controls */
  3070.     if (becomingActive)
  3071.     {
  3072.         if ((theWindow == gSrcWind_Window) && (gSrcWind_Window != NULL))
  3073.         {
  3074.             TEActivate(gSrcWind_TEH);
  3075.             ShowControl(gSrcWind_VScroll);
  3076.         }
  3077.         else
  3078.         {
  3079.             if ((theWindow == (WindowPtr)gp2wWindow) && (gp2wWindow))
  3080.                 p2w_DoActivate(gp2wWindow, becomingActive);
  3081.         }
  3082.     }
  3083.     else
  3084.     {
  3085.         if ((theWindow == gSrcWind_Window) && (gSrcWind_Window != NULL))
  3086.         {
  3087.             TEDeactivate(gSrcWind_TEH);
  3088.             HideControl(gSrcWind_VScroll);
  3089.         }
  3090.         else
  3091.         {
  3092.             if ((theWindow == (WindowPtr)gp2wWindow) && (gp2wWindow))
  3093.                 p2w_DoActivate(gp2wWindow, becomingActive);
  3094.         }
  3095.     }
  3096. } // HandleActivate
  3097.  
  3098.  
  3099.  
  3100. // ---------------------------------------------------------------------
  3101. // Set up the undo buffers
  3102. static void init_undo_system()
  3103. {
  3104.     int i;
  3105.     for (i = 0; i <= max_undo; i++)
  3106.     {
  3107.         undo_record[i].buf_handle = NULL;
  3108.         undo_record[i].reason[0] = 0;
  3109.     }
  3110.     undo_key_copied = 0;
  3111. } // init_undo_system
  3112.  
  3113.  
  3114.  
  3115. // ---------------------------------------------------------------------
  3116. // Set up the redo buffers
  3117. static void init_redo_system()
  3118. {
  3119.     int i;
  3120.     for (i = 0; i <= max_undo; i++)
  3121.     {
  3122.         redo_record[i].buf_handle = NULL;
  3123.         redo_record[i].reason[0] = 0;
  3124.     }
  3125. } // init_redo_system
  3126.  
  3127.  
  3128.  
  3129. // ---------------------------------------------------------------------
  3130. // Dispose of all the undo buffers
  3131. static void flush_undo_system(void)
  3132. {
  3133.     int i;
  3134.     for (i = 0; i <= max_undo; i++)
  3135.     {
  3136.         if (undo_record[i].buf_handle)
  3137.         {
  3138.             DisposeHandle(undo_record[i].buf_handle);
  3139.             undo_record[i].buf_handle = NULL;
  3140.         }
  3141.         undo_record[i].reason[0] = 0;
  3142.     }
  3143.     undo_key_copied = 0;
  3144. } // flush_undo_system
  3145.  
  3146.  
  3147.  
  3148. // ---------------------------------------------------------------------
  3149. // Dispose of all the redo buffers
  3150. static void flush_redo_system(void)
  3151. {
  3152.     int i;
  3153.     for (i = 0; i <= max_undo; i++)
  3154.     {
  3155.         if (redo_record[i].buf_handle)
  3156.         {
  3157.             DisposeHandle(redo_record[i].buf_handle);
  3158.             redo_record[i].buf_handle = NULL;
  3159.         }
  3160.         redo_record[i].reason[0] = 0;
  3161.     }
  3162. } // flush_redo_system
  3163.  
  3164.  
  3165.  
  3166. // ---------------------------------------------------------------------
  3167. // get rid of all undo buffers
  3168. static short free_undo_memory(void)
  3169. {
  3170.     short    i;
  3171.     /* from the oldest to newest (except the last), dispose the Undo & redo buffers */
  3172.     for (i = 0; i < max_undo; i++)
  3173.     {
  3174.         if (redo_record[i].buf_handle)
  3175.         {
  3176.             DisposeHandle(redo_record[i].buf_handle);
  3177.             redo_record[i].buf_handle = 0;
  3178.             redo_record[i].reason[0] = 0;
  3179.             return (1);
  3180.         }            
  3181.         if (undo_record[i].buf_handle)
  3182.         {
  3183.             DisposeHandle(undo_record[i].buf_handle);
  3184.             undo_record[i].buf_handle = 0;
  3185.             undo_record[i].reason[0] = 0;
  3186.             return (1);
  3187.         }
  3188.     }
  3189.     return (0);
  3190. } // free_undo_memory
  3191.  
  3192.  
  3193.  
  3194. // ---------------------------------------------------------------------
  3195. // Support undo by duplicating the current file's text as necessary
  3196. void support_undo(char *the_reason, short flush_redo)
  3197. {
  3198.     int i;
  3199.     char *buffer;
  3200.  
  3201.     /* new changes are being made to the file.  Redo no longer makes sense. */
  3202.     if (flush_redo)
  3203.         flush_redo_system();
  3204.  
  3205.     /* Dispose oldest undo record storage, because the record will be destroyed. */
  3206.     if (undo_record[0].buf_handle)
  3207.         DisposeHandle(undo_record[0].buf_handle);
  3208.  
  3209.     /* block-move the records down to make room for a new undo entry */
  3210.     for (i = 0; i < max_undo; i++)
  3211.         undo_record[i] = undo_record[i+1];
  3212.  
  3213.     /* Try repeatedly to allocate memory for the undo buffer, disposing old */
  3214.     /* undo buffers as necessary. */
  3215.  
  3216. TRY_AGAIN:
  3217.     undo_record[max_undo].buf_handle = (char **) NewHandle((**gSrcWind_TEH).teLength);
  3218.     if (undo_record[max_undo].buf_handle == 0)
  3219.         if (free_undo_memory()) goto TRY_AGAIN;
  3220.  
  3221.     if (undo_record[max_undo].buf_handle == 0)
  3222.     {
  3223.         undo_record[max_undo].reason[0] = 0;
  3224.         return;
  3225.     }
  3226.     HLock(undo_record[max_undo].buf_handle);
  3227.     buffer = *(undo_record[max_undo].buf_handle);
  3228.     undo_record[max_undo].selStart = (**gSrcWind_TEH).selStart;
  3229.     undo_record[max_undo].selEnd = (**gSrcWind_TEH).selEnd;
  3230.     strcpy(undo_record[max_undo].reason, the_reason);
  3231.     strcpy(undo_menu_name, "Undo ");
  3232.     strcat(undo_menu_name, the_reason);
  3233.     c2pstr(undo_menu_name);
  3234.     SetItem(myMenus[edmn_ID - menu_offset], edmn_undo, (StringPtr)undo_menu_name);
  3235.     undo_record[max_undo].byteCount = (**gSrcWind_TEH).teLength;
  3236.     undo_record[max_undo].isDirty = gSrcWind_dirty;
  3237.     memcpy(buffer, *(**gSrcWind_TEH).hText, (**gSrcWind_TEH).teLength);
  3238.     HUnlock(undo_record[max_undo].buf_handle);
  3239.     undo_key_copied = 0;
  3240. } // support_undo
  3241.  
  3242.  
  3243.  
  3244. // ---------------------------------------------------------------------
  3245. // Support redo by duplicating the current file's text as necessary
  3246. static void support_redo(char *the_reason)
  3247. {
  3248.     int i;
  3249.     char *buffer;
  3250.  
  3251.     /* Dispose oldest redo record storage, because the record will be destroyed. */
  3252.     if (redo_record[0].buf_handle)
  3253.         DisposeHandle(redo_record[0].buf_handle);
  3254.  
  3255.     /* block-move the records down to make room for a new redo entry */
  3256.     for (i = 0; i < max_undo; i++)
  3257.         redo_record[i] = redo_record[i+1];
  3258.  
  3259.     /* Try repeatedly to allocate memory for the redo buffer, disposing old */
  3260.     /* redo buffers as necessary. */
  3261. TRY_AGAIN:
  3262.     redo_record[max_undo].buf_handle = (char **) NewHandle((**gSrcWind_TEH).teLength);
  3263.     if (redo_record[max_undo].buf_handle == 0)
  3264.         if (free_undo_memory()) goto TRY_AGAIN;
  3265.  
  3266.     if (redo_record[max_undo].buf_handle == 0)
  3267.     {
  3268.         redo_record[max_undo].reason[0] = 0;
  3269.         return;
  3270.     }
  3271.     HLock(redo_record[max_undo].buf_handle);
  3272.     buffer = *(redo_record[max_undo].buf_handle);
  3273.     redo_record[max_undo].selStart = (**gSrcWind_TEH).selStart;
  3274.     redo_record[max_undo].selEnd = (**gSrcWind_TEH).selEnd;
  3275.     strcpy(redo_record[max_undo].reason, the_reason);
  3276.     strcpy(redo_menu_name, "Redo ");
  3277.     strcat(redo_menu_name, the_reason);
  3278.     c2pstr(redo_menu_name);
  3279.     SetItem(myMenus[edmn_ID - menu_offset], edmn_redo, (StringPtr)redo_menu_name);
  3280.     redo_record[max_undo].byteCount = (**gSrcWind_TEH).teLength;
  3281.     redo_record[max_undo].isDirty = gSrcWind_dirty;
  3282.     memcpy(buffer, *(**gSrcWind_TEH).hText, (**gSrcWind_TEH).teLength);
  3283.     HUnlock(redo_record[max_undo].buf_handle);
  3284. } // support_redo
  3285.  
  3286.  
  3287.  
  3288. // ---------------------------------------------------------------------
  3289. // Show that we can undo previous typing
  3290. static void support_undo_key(void)
  3291. {
  3292.     if (undo_key_copied == 0)
  3293.     {
  3294.         support_undo("Typing", TRUE);
  3295.         undo_key_copied = 1;
  3296.     }
  3297. } // support_undo_key
  3298.  
  3299.  
  3300.  
  3301. // ---------------------------------------------------------------------
  3302. // Actually do the undo operation on the source file
  3303. static void undo_text()
  3304. {
  3305.     int i;
  3306.     char *buffer;
  3307.     if (undo_record[max_undo].reason[0])
  3308.     {
  3309.         support_redo(undo_record[max_undo].reason);
  3310.         (**gSrcWind_TEH).selStart = 0;
  3311.         (**gSrcWind_TEH).selEnd = (**gSrcWind_TEH).teLength;
  3312.         TEDelete(gSrcWind_TEH);
  3313.         HLock(undo_record[max_undo].buf_handle);
  3314.         buffer = *(undo_record[max_undo].buf_handle);
  3315.         TEInsert(buffer, undo_record[max_undo].byteCount, gSrcWind_TEH);
  3316.         undo_key_copied = 0;
  3317.         TESetSelect(undo_record[max_undo].selStart, undo_record[max_undo].selEnd, gSrcWind_TEH);
  3318.         gSrcWind_dirty = undo_record[max_undo].isDirty;
  3319.         InvalRect(&gSrcWind_Window->portRect);
  3320.         ShowSelect();
  3321.  
  3322.         /* dispose of the current undo record's data */
  3323.         DisposeHandle(undo_record[max_undo].buf_handle);
  3324.  
  3325.         /* move other undo records up the chain. */
  3326.         for (i = max_undo; i > 0; i--)
  3327.             undo_record[i] = undo_record[i-1];
  3328.  
  3329.         /* Delete the contents of the (duplicated) last record */
  3330.         undo_record[0].buf_handle = 0;
  3331.         undo_record[0].reason[0] = 0;
  3332.  
  3333.         /* show everyone what the next undoable item will be */
  3334.         strcpy(undo_menu_name, "Undo ");
  3335.         strcat(undo_menu_name, undo_record[max_undo].reason);
  3336.         c2pstr(undo_menu_name);
  3337.         SetItem(myMenus[edmn_ID - menu_offset], edmn_undo, (StringPtr)undo_menu_name);
  3338.     }
  3339. } // undo_text
  3340.  
  3341.  
  3342.  
  3343. // ---------------------------------------------------------------------
  3344. // Actually do the redo operation on the text file
  3345. static void redo_text()
  3346. {
  3347.     int i;
  3348.     char *buffer;
  3349.     if (redo_record[max_undo].reason[0])
  3350.     {
  3351.         support_undo(redo_record[max_undo].reason, false);
  3352.         (**gSrcWind_TEH).selStart = 0;
  3353.         (**gSrcWind_TEH).selEnd = (**gSrcWind_TEH).teLength;
  3354.         TEDelete(gSrcWind_TEH);
  3355.         HLock(redo_record[max_undo].buf_handle);
  3356.         buffer = *(redo_record[max_undo].buf_handle);
  3357.         TEInsert(buffer, redo_record[max_undo].byteCount, gSrcWind_TEH);
  3358.         undo_key_copied = 0;
  3359.         TESetSelect(redo_record[max_undo].selStart, redo_record[max_undo].selEnd, gSrcWind_TEH);
  3360.         gSrcWind_dirty = redo_record[max_undo].isDirty;
  3361.         ShowSelect();
  3362.  
  3363.         /* dispose of the current undo record's data */
  3364.         DisposeHandle(redo_record[max_undo].buf_handle);
  3365.  
  3366.         /* move other undo records up the chain. */
  3367.         for (i = max_undo; i > 0; i--)
  3368.             redo_record[i] = redo_record[i-1];
  3369.  
  3370.         /* Delete the contents of the (duplicated) last record */
  3371.         redo_record[0].buf_handle = 0;
  3372.         redo_record[0].reason[0] = 0;
  3373.  
  3374.         /* show everyone what the next redoable item will be */
  3375.         strcpy(redo_menu_name, "Redo ");
  3376.         strcat(redo_menu_name, redo_record[max_undo].reason);
  3377.         c2pstr(redo_menu_name);
  3378.         SetItem(myMenus[edmn_ID - menu_offset], edmn_redo, (StringPtr)redo_menu_name);
  3379.     }
  3380. } // redo_text
  3381.  
  3382.  
  3383.  
  3384. // ---------------------------------------------------------------------
  3385. // Display additional credits on POV-Ray startup
  3386. void PrintMacCredits(void)
  3387. {
  3388.     char    appVers[32];
  3389.  
  3390.     fprintf (stderr,"  This Macintosh implementation of POV-Ray is brought to you by:\n");
  3391.     fprintf (stderr,"       David Harr         Jim Nitchals       Eduard [esp] Schwan\n");
  3392.  
  3393.     fprintf (stderr,"  Macintosh Beta Testing by:\n");
  3394.     fprintf (stderr,"       Mark de Jong       Anton Raves\n");
  3395.  
  3396.     GetAppVersionPString(1, (StringPtr)appVers);
  3397.     p2cstr((StringPtr)appVers);
  3398.     fprintf (stderr,"\n");
  3399.     fprintf (stderr,"  POV-Ray version %s [%s]\n", appVers,COMPILER_VER);
  3400.  
  3401.     fprintf (stderr,"  ----------------------------------------------------------------------\n");
  3402. } // PrintMacCredits
  3403.  
  3404.  
  3405.  
  3406. // ---------------------------------------------------------------------
  3407. // This is what is really called if exit() is called
  3408. void catch_exit(int n)
  3409. {
  3410.     gRenderedOK = 0;
  3411.     // if error & in main file, then go to line #
  3412.     if ((n == 1) && (Include_File_Index == 0))
  3413.     {
  3414.         // Show source window, and hilite line #
  3415.         SelectWindow(gSrcWind_Window);
  3416.         goto_line(Token.Token_Line_No+1);
  3417.     }
  3418.  
  3419.     HaltFileQ();
  3420.  
  3421.     longjmp(gSetJmpEnv, 1);
  3422. } // catch_exit
  3423.  
  3424.  
  3425.  
  3426. // ---------------------------------------------------------------------
  3427. // Moves and sizes the window passed to fit the Rect passed.
  3428. // No checking is done to see that it fits on a screen.
  3429. void MoveSizeWindow(WindowPtr pWindow, Rect * pWindRect)
  3430. {
  3431.     // position & size the window
  3432.     MoveWindow(pWindow, pWindRect->left, pWindRect->top, false);
  3433.     // oh the grodiest hack for now... someday, all windows will be equal!
  3434.     // until then, we gotta put up with the skanky editor window.
  3435.     if (pWindow == gSrcWind_Window)
  3436.         MyResizeWindow(pWindow, pWindRect->right - pWindRect->left, pWindRect->bottom - pWindRect->top);
  3437.     else
  3438.         SizeWindow(pWindow, pWindRect->right - pWindRect->left, pWindRect->bottom - pWindRect->top, false);
  3439. } // MoveSizeWindow
  3440.  
  3441.  
  3442. // ---------------------------------------------------------------------
  3443. // positions and displays a new source window.
  3444. void OpenNewSourceWindow(void)
  3445. {
  3446.     // set up window title to be file name
  3447.     SetWTitle(gSrcWind_Window, gSrcWind_FileName);
  3448.  
  3449.     // Set Image window to saved position, shown later when render starts
  3450.     MoveSizeWindow(gImageWindowPtr, &(**gFilePrefs_h).imageWind_pos);
  3451.  
  3452.     // Set Source window position to saved position & show it
  3453.     MoveSizeWindow(gSrcWind_Window, &(**gFilePrefs_h).srcWind_pos);
  3454.     ShowWindow(gSrcWind_Window);
  3455.  
  3456.     // bring to front if splash screen not up
  3457.     if (!gSplashScreen)
  3458.         SelectWindow(gSrcWind_Window);
  3459.  
  3460.     gSrcWind_visible = TRUE;
  3461.     gSrcWind_dirty = 0;
  3462.     TESetSelect(0, 0, gSrcWind_TEH);
  3463.     ShowSelect();
  3464. } // OpenNewSourceWindow
  3465.  
  3466.  
  3467. // ---------------------------------------------------------------------
  3468. // Convert a vref/dirID into a magic vref (working dir)
  3469. static OSErr MyDirID2VrefNum(short vRefNum, long dirID, short *theWDVrefNumPtr)
  3470. {
  3471.     OSErr            anError;
  3472.  
  3473.     // Open a Working directory for ourselves.  Note that we leave
  3474.     // it open forever (just like SFGetFile does.)  This is supposed
  3475.     // to be kosher, the Finder is to clean up after us when we quit!?
  3476.     anError = OpenWD(vRefNum, dirID, kAppSignature, theWDVrefNumPtr);
  3477.     return anError;
  3478. } // MyDirID2VrefNum
  3479.  
  3480.  
  3481.  
  3482. // ---------------------------------------------------------------------
  3483. // General entry to open a source file for editing
  3484. static void OpenTextFile(Str255 fn, short vRef, long dirID, Boolean UseDirID)
  3485. {
  3486.     short    fRefNum, vRefNum;
  3487.     int        errcode = noErr;
  3488.  
  3489.     // close any existing file first
  3490.     CloseMyWindow();
  3491.  
  3492.     // If ODOC, find working dir from vref/dirID so we can use FSOpen etc.
  3493.     if (UseDirID)
  3494.     {
  3495.         // convert vref/dirID into WD vrefnum for later FSOpen and SetVol calls
  3496.         errcode = MyDirID2VrefNum(vRef, dirID, &vRefNum);
  3497.     }
  3498.     else
  3499.     {
  3500.         vRefNum = vRef;
  3501.     }
  3502.  
  3503.     if (errcode==noErr)
  3504.         errcode = FSOpen(fn, vRefNum, &fRefNum);
  3505.     if (errcode==noErr)
  3506.     {
  3507.         flush_undo_system();
  3508.         errcode = ReadFile(fRefNum, gSrcWind_TEH);
  3509.         FSClose(fRefNum);    /* and ignore close errors */
  3510.         if (errcode == 999)
  3511.             FileError("\pFile too large to be edited: ", fn);
  3512.         if (errcode == 1) 
  3513.         {
  3514.             pStrCopy(fn, gSrcWind_FileName);
  3515.             gSrcWind_VRefNum = vRefNum;
  3516.             GetFilePrefs();
  3517.             OpenNewSourceWindow();
  3518.         }
  3519.     }
  3520.     else
  3521.         FileError("\pError opening ", fn);
  3522.  
  3523. } // OpenTextFile
  3524.  
  3525.  
  3526.  
  3527. // ---------------------------------------------------------------------
  3528. // Save the status window text into a new text file
  3529. static int Save_StatusWindow(void)
  3530. {
  3531.     OSErr    ioError;
  3532.     char    hstate;
  3533.     short    vRef = 0;
  3534.     short    refNum;
  3535.     char    fn[] = "\pPOV-Ray Status.Window";
  3536.  
  3537.     SetCursor(&gWaitCursor); // could take a little while..
  3538.  
  3539.     ioError = FSDelete((StringPtr)fn, vRef); 
  3540.     ioError = Create((StringPtr)fn, vRef, 'ttxt', 'TEXT');
  3541.     if ((ioError == noErr) || (ioError == dupFNErr))
  3542.         ioError = FSOpen((StringPtr)fn, vRef, &refNum);
  3543.     if (ioError)
  3544.     {
  3545.         SetCursor(&qd.arrow);
  3546.         FileError("\pError creating Status file ", (StringPtr)fn);
  3547.         return (0);
  3548.     }
  3549.     else
  3550.     {
  3551.         hstate = HGetState((**gp2wWindow->p2wTEHandle).hText);
  3552.         HLock((**gp2wWindow->p2wTEHandle).hText);
  3553.  
  3554.         if (WriteFile(refNum, (*(**gp2wWindow->p2wTEHandle).hText),
  3555.                         (long)(**gp2wWindow->p2wTEHandle).teLength))
  3556.             FileError("\pError writing file ", (StringPtr)fn);
  3557.  
  3558.         HSetState((**gp2wWindow->p2wTEHandle).hText, hstate);
  3559.  
  3560.         FSClose(refNum);
  3561.  
  3562.         SetCursor(&qd.arrow); // all done
  3563.         return(1);
  3564.     }
  3565. } // Save_StatusWindow
  3566.  
  3567.  
  3568.  
  3569. // ---------------------------------------------------------------------
  3570. // Done rendering, beep if in background, or auto-shutdown if requested
  3571. static void notify_user(void)
  3572. {
  3573.     Boolean        doFeedback = false;
  3574.     Boolean        doBeep = false;
  3575.     Boolean        doDialog = false;
  3576.  
  3577.     if (gRenderedOK)
  3578.         SetCustomPalette(!gInBackground);
  3579.  
  3580.     /* If the image rendered OK and shutdown was requested, then shut down. */
  3581.     if (gAutoShutdown  &&  gRenderedOK)
  3582.     {
  3583.         Save_StatusWindow();    /* save status window too */
  3584.         DoShutdownMac();
  3585.     }
  3586.     else
  3587.     { // check for feedback
  3588.  
  3589.         // are we going to give user feedback?
  3590.         switch ((**gAppPrefs_h).whenToNotify)
  3591.         {
  3592.             case eWhenNtf_Quiet:    // don't notify at all when done
  3593.                 break;
  3594.             case eWhenNtf_BgOnly:    // notify when done, only if in background
  3595.                 doFeedback = gInBackground;
  3596.                 break;
  3597.             case eWhenNtf_FgOnly:    // notify when done, only if in foreground
  3598.                 doFeedback = !gInBackground;
  3599.                 break;
  3600.             case eWhenNtf_BgFg:        // notify when done, in background or foreground
  3601.                 doFeedback = true;
  3602.                 break;
  3603.         } // switch
  3604.  
  3605.         // do the beep, dialog, or both?
  3606.         if (doFeedback)
  3607.         {
  3608.             switch ((**gAppPrefs_h).howToNotify)
  3609.             {
  3610.                 case eHowNtf_Noise:    // do noise
  3611.                     doBeep = true;
  3612.                     break;
  3613.                 case eHowNtf_Dlg:    // do dialog
  3614.                     doDialog = true;
  3615.                     break;
  3616.                 case eHowNtf_NoiseDlg:    // do noise & dialog
  3617.                     doBeep = true;
  3618.                     doDialog = true;
  3619.                     break;
  3620.             } // switch
  3621.         } // if doFeedback
  3622.     } // else check for feedback
  3623.  
  3624.     // get everyone's attention...
  3625.     if (doBeep)
  3626.         PlayNotifySound();
  3627.     if (doDialog)
  3628.         ShowNotifyDialog();
  3629.  
  3630. } // notify_user
  3631.  
  3632.  
  3633.  
  3634. // ---------------------------------------------------------------------
  3635. // Get and display the intro splash screen
  3636. static void CreateSplashScreen()
  3637. {
  3638.     char    povVers[16];
  3639.     gSplashStartTicks = 0;
  3640.     gSplashScreen = GetNewDialog(138, NULL, (WindowPtr) -1);
  3641.     if (gSplashScreen != NULL)
  3642.     {
  3643.         gSplashStartTicks = TICKS;
  3644.         strcpy(povVers, POV_RAY_VERSION);
  3645.         c2pstr(povVers);
  3646.  
  3647.         ParamText((StringPtr)povVers, gDistMessage, "\p", "\p");
  3648.         SetPort((GrafPtr)gSplashScreen);
  3649.  
  3650.         TextFont(times);
  3651.         TextSize(12);
  3652.  
  3653.         PositionWindow(gSplashScreen, ewcDoCentering, eDeepestDevice, (WindowPtr)gp2wWindow);
  3654.         ShowWindow(gSplashScreen);
  3655.         SelectWindow(gSplashScreen);
  3656.         DrawDialog(gSplashScreen);
  3657.     }
  3658. }
  3659.  
  3660.  
  3661.  
  3662. // ---------------------------------------------------------------------
  3663. // close and dispose of the intro splash screen
  3664. static void KillSplashScreen(void)
  3665. {
  3666.     if (gSplashScreen)
  3667.         DisposeDialog(gSplashScreen);
  3668.     gSplashScreen = NULL;
  3669.     gSplashStartTicks = 0;
  3670.  
  3671.     // bring source window to front now
  3672.     if (gSrcWind_Window)
  3673.         SelectWindow(gSrcWind_Window);
  3674.  
  3675. } // KillSplashScreen
  3676.  
  3677.  
  3678.  
  3679. // ---------------------------------------------------------------------
  3680. // create and display a new empty source window
  3681. static void DoFile_New(void)
  3682. {
  3683.     // close any existing file
  3684.     CloseMyWindow();
  3685.  
  3686.     // set up untitled
  3687.     SetUpFiles();
  3688.  
  3689.     // new file gets default prefs
  3690.     **gFilePrefs_h = **gDefltFilePrefs_h;
  3691.  
  3692.     OpenNewSourceWindow();
  3693.  
  3694. } // DoFile_New
  3695.  
  3696.  
  3697.  
  3698. // ---------------------------------------------------------------------
  3699. // Prompt user for a source file, and open it into source window
  3700. static void DoFile_Open(void)
  3701. {
  3702.     short    vRef = 0;
  3703.     Str255     fn;
  3704.  
  3705.     if (OldFile(fn, &vRef))
  3706.     {
  3707.         OpenTextFile(fn, vRef, 0L, false/*!UseDirID*/);    
  3708.     }
  3709. } // DoFile_Open
  3710.  
  3711.  
  3712.  
  3713. // ---------------------------------------------------------------------
  3714. // Set up, call the renderer, and notify user when done
  3715. static void DoRendering(void)
  3716. {
  3717.     Boolean    stillDoingAnimation;
  3718.     long    start_ticks;
  3719.     short    animFrameNumber;
  3720.  
  3721.     if (gSrcWind_dirty)
  3722.         if (DoFile(fmn_save))
  3723.             ;
  3724.  
  3725.     gInAnimationLoop = (**gPrefs2Use_h).doAnimation;
  3726.     gAnimRec = (**gPrefs2Use_h).animRec;
  3727.     SetCurrFrameVal(&gAnimRec, gAnimRec.frameValS);
  3728.     stillDoingAnimation = gInAnimationLoop;
  3729.  
  3730.     do    {
  3731.         SetupRenderArgs();
  3732.  
  3733.         if ( stillDoingAnimation && ((**gPrefs2Use_h).progress >= kProgMinimal) )
  3734.         {
  3735.             printf("-- [Animation] StartFrame=%d,  EndFrame=%d, CurrFrame=%d, CurrClock=%g)\n",
  3736.                 gAnimRec.frameValS, gAnimRec.frameValE, GetCurrFrameVal(), GetCurrClockVal());
  3737.         }
  3738.  
  3739.         start_ticks = TICKS;
  3740.  
  3741.         // pull status window to front (not user-friendly, but user-requested!)
  3742.         SelectWindow((WindowPtr)gp2wWindow);
  3743.  
  3744.         // Do the real POV-Ray work now
  3745.         call_main(ARGC, ARGV);
  3746.  
  3747.         // Give a quick breath after each render
  3748.         Cooperate(true);
  3749.  
  3750.         // write PICT file with current name.PICT
  3751.         if    (
  3752.             (gAutoSave || gAutoShutdown || gInAnimationLoop || gDoingBatchODOCs)
  3753.             &&  gRenderedOK && !Stop_Flag && !gQuit
  3754.             )
  3755.         {
  3756.             // set up frame # suffix (if any)
  3757.             if (gInAnimationLoop)
  3758.                 animFrameNumber = GetCurrFrameVal();
  3759.             else
  3760.                 animFrameNumber = kNoAnimSuffix;
  3761.             // save the image
  3762.             SaveOutputFile(false, animFrameNumber, gtheSCComponent);
  3763.         }
  3764.  
  3765.         // next frame
  3766.         if (gInAnimationLoop)
  3767.             stillDoingAnimation = IncToNextFrame(&gAnimRec);
  3768.     } while (stillDoingAnimation && !Stop_Flag && !gQuit);
  3769.  
  3770.     gInAnimationLoop = false;
  3771.  
  3772.     /*
  3773.     If POV wasn't prematurely stopped, and if it is not in the middle of multiple renders,
  3774.     then call the notification procedure.
  3775.     */
  3776.     if    (!Stop_Flag && (FileQ_NumItems() == 0))
  3777.         notify_user();
  3778.  
  3779.     gBeginRendering = false; // all done for now
  3780. } // DoRendering
  3781.  
  3782.  
  3783.  
  3784. // ---------------------------------------------------------------------
  3785. // Open a source file, render it, save the image PICT, and close the source file
  3786. static void BatchProcessOneFile(FSSpec    *pFile)
  3787. {
  3788.     gDoingBatchODOCs = true; // postpone other ODOCs until done with this one!
  3789.  
  3790.     OpenTextFile(pFile->name, pFile->vRefNum, pFile->parID, true/*UseDirID*/);
  3791.     DoRendering();
  3792.     DoFile(fmn_close);
  3793.  
  3794.     gDoingBatchODOCs = false;
  3795. } // BatchProcessOneFile
  3796.  
  3797.  
  3798.  
  3799. // ---------------------------------------------------------------------
  3800. // Handle choosing items from the File menu
  3801. static void DoFileMenu(short theItem)
  3802. {
  3803.     WindowPtr    theFrontWindow;
  3804.  
  3805.     theFrontWindow = FrontWindow();
  3806.     switch (theItem)
  3807.     {
  3808.         case fmn_new:                                /* New File */
  3809.                 DoFile_New();
  3810.                 break;
  3811.  
  3812.         case fmn_open:                                 /* Open a file */
  3813.                 DoFile_Open();
  3814.                 break;
  3815.  
  3816.         case fmn_close:                                /* Close */
  3817.                 if (theFrontWindow == gImageWindowPtr)
  3818.                     CloseImageWindow();
  3819.                 else if (theFrontWindow == gSrcWind_Window)
  3820.                     DoFile(fmn_close);
  3821.                 break;
  3822.  
  3823.         case fmn_save:                            /* Save */
  3824.                 if (theFrontWindow == gSrcWind_Window)
  3825.                 {    
  3826.                     if (DoFile(fmn_save))
  3827.                         WriteFilePrefs();                            
  3828.                 }                        
  3829.                 else if (theFrontWindow == gImageWindowPtr)
  3830.                         SaveOutputFile(false, kNoAnimSuffix, gtheSCComponent); // don't prompt for name
  3831.                 else if (theFrontWindow == (WindowPtr)gp2wWindow)
  3832.                     Save_StatusWindow();
  3833.                 break;
  3834.  
  3835.         case fmn_saveas:                            /* Save as… */
  3836.                 if (theFrontWindow == gSrcWind_Window)
  3837.                 {    
  3838.                     if (DoFile(fmn_saveas))
  3839.                     {
  3840.                         // this will have no settings, so write existing file prefs to it
  3841.                         WriteFilePrefs();                            
  3842.                     }
  3843.                 }
  3844.                 else if (theFrontWindow == gImageWindowPtr)
  3845.                     SaveOutputFile(true, kNoAnimSuffix, gtheSCComponent); // prompt for name
  3846.                 else if (theFrontWindow == (WindowPtr)gp2wWindow)
  3847.                     Save_StatusWindow();
  3848.                 break;
  3849.  
  3850.         case fmn_quit:
  3851.                 ask_about_quit();
  3852.                 if (gQuit)
  3853.                     if (DoFile(fmn_close))
  3854.                         ;
  3855.                 break;    /* Quit the program */
  3856.     }
  3857. } // DoFileMenu
  3858.  
  3859.  
  3860.  
  3861. // ---------------------------------------------------------------------
  3862. // Handle choosing items from the Edit menu
  3863. static void DoEditMenu(short theItem)
  3864. {
  3865.     WindowPtr    theFrontWindow;
  3866.  
  3867.     theFrontWindow = FrontWindow();
  3868.  
  3869.     if (SystemEdit(theItem-1) != 0)
  3870.         return;
  3871.  
  3872.     /* handle the menu items for the front window */
  3873.         switch (theItem)
  3874.         {
  3875.             case edmn_undo:                    /*undo*/
  3876.                 if (theFrontWindow == gSrcWind_Window)
  3877.                 {
  3878.                     undo_text();
  3879.                     AdjustText();
  3880.                 }
  3881.                 else if (theFrontWindow == gImageWindowPtr)
  3882.                 {
  3883.                     if (gCanUndo)
  3884.                         undo_image();
  3885.                 }
  3886.                 break;
  3887.  
  3888.             case edmn_cut:
  3889.                 support_undo("Cut", TRUE);
  3890.                 ZeroScrap(); // clear out the clipboard
  3891.                 TECut(gSrcWind_TEH);
  3892.                 TEToScrap(); // export
  3893.                 AdjustText();
  3894.                 gSrcWind_dirty = 1;
  3895.                 break;
  3896.  
  3897.             case edmn_copy:                    /*copy*/
  3898.                 if (theFrontWindow == gSrcWind_Window)
  3899.                 {
  3900.                     ZeroScrap(); // clear out the clipboard
  3901.                     TECopy(gSrcWind_TEH);
  3902.                     TEToScrap(); // export
  3903.                 }
  3904.                 else if (theFrontWindow == gImageWindowPtr)
  3905.                 {
  3906.                     ZeroScrap(); // clear out the clipboard
  3907.                     paint_to_picture(false);
  3908.                     TEToScrap(); // export
  3909.                 }
  3910.                 else if (theFrontWindow == (WindowPtr)gp2wWindow)
  3911.                 {
  3912.                     ZeroScrap(); // clear out the clipboard
  3913.                     TECopy(gp2wWindow->p2wTEHandle);
  3914.                     TEToScrap(); // export
  3915.                 }
  3916.                 break;
  3917.     
  3918.             case edmn_paste:
  3919.                 support_undo("Paste", TRUE);
  3920.                 TEFromScrap(); // import
  3921.                 TEPaste(gSrcWind_TEH);
  3922.                 AdjustText();
  3923.                 gSrcWind_dirty = 1;
  3924.                 break;
  3925.  
  3926.             case edmn_clear:
  3927.                 support_undo("Clear", TRUE);
  3928.                 TEDelete(gSrcWind_TEH);
  3929.                 AdjustText();
  3930.                 gSrcWind_dirty = 1;
  3931.                 break;
  3932.  
  3933.             case edmn_selectAll:
  3934.                 if (theFrontWindow == gSrcWind_Window)
  3935.                 {
  3936.                     SelectAllText();
  3937.                 }
  3938.                 else if (theFrontWindow == (WindowPtr)gp2wWindow)
  3939.                 {
  3940.                     p2w_SelectAll(gp2wWindow);
  3941.                 }
  3942.                 break;
  3943.  
  3944.             case edmn_redo:
  3945.                 redo_text();
  3946.                 AdjustText();
  3947.                 break;
  3948.  
  3949.             case edmn_goto:
  3950.                 choose_goto_line();
  3951.                 break;
  3952.  
  3953.             case edmn_lookup:
  3954.                 DoLookup();
  3955.                 break;
  3956.  
  3957.             case edmn_prefs:
  3958.                 ChangeAppPrefs();
  3959.                 break;
  3960.         } /*switch*/
  3961. } // DoEditMenu
  3962.  
  3963.  
  3964.  
  3965. // ---------------------------------------------------------------------
  3966. // Handle choosing items from various menus
  3967. static void DoCommand(long m)
  3968. {
  3969.     short        theMenu, theItem;
  3970.     Str255        name;
  3971.  
  3972.     theMenu = (m >> 16);
  3973.     theItem = m;
  3974.     switch (theMenu)
  3975.     {
  3976.         case apmn_ID:                /* Apple Menu */
  3977.             if (theItem == apmn_about)
  3978.                 AboutPOV();
  3979.             else
  3980.             {
  3981.                 GetItem(myMenus[apmn_ID - menu_offset], theItem, name);
  3982.                 OpenDeskAcc(name);
  3983.             }
  3984.             break;
  3985.             
  3986.         case fmn_ID:                /* File Menu */
  3987.             DoFileMenu(theItem);
  3988.             break;
  3989.  
  3990.         case edmn_ID:                /* Edit Menu */
  3991.             DoEditMenu(theItem);
  3992.             break;
  3993.  
  3994.         case immn_ID:                /* Image Menu */
  3995.             if (theItem == immn_dither)
  3996.             {
  3997.                 // toggle it
  3998.                 (**gPrefs2Use_h).doDither = !(**gFilePrefs_h).doDither;
  3999.                 // make sure file prefs are updated too (in case using app prefs)
  4000.                 (**gFilePrefs_h).doDither = (**gPrefs2Use_h).doDither;
  4001.                 InvalRect_ImageWindow(false);
  4002.                 break;
  4003.             }
  4004.             break;
  4005.  
  4006.         case viewmn_ID:                /* View submenu */
  4007.             (**gFilePrefs_h).imageMagFactor = theItem;
  4008.             // make sure current is same as file (in case using app prefs)
  4009.             (**gPrefs2Use_h).imageMagFactor = (**gFilePrefs_h).imageMagFactor;
  4010.             SetImageWindowMag(theItem);
  4011.             break;
  4012.  
  4013.         case plmn_ID:                /* Custom Palette submenu */
  4014.             switch(theItem)
  4015.             {
  4016.                 case palette_none:
  4017.                     use_custom_palette = false;
  4018.                     gColorQuantMethod = -1;
  4019.                     break;
  4020.  
  4021.                 case palette_default:
  4022.                     use_custom_palette = true;
  4023.                     gColorQuantMethod = systemMethod;
  4024.                     break;
  4025.  
  4026.                 case palette_median:
  4027.                     use_custom_palette = true;
  4028.                     gColorQuantMethod = medianMethod;
  4029.                     break;
  4030.  
  4031.                 case palette_popular:
  4032.                     use_custom_palette = true;
  4033.                     gColorQuantMethod = popularMethod;
  4034.                     break;
  4035.  
  4036.                 case palette_var_min:
  4037.                     use_custom_palette = true;
  4038.                     gColorQuantMethod = varianceMethod;
  4039.                     break;
  4040.  
  4041.                 case palette_octree:
  4042.                     use_custom_palette = true;
  4043.                     gColorQuantMethod = octreeMethod;
  4044.                     break;
  4045.             }
  4046.  
  4047.             if (((WindowPeek)gImageWindowPtr)->visible)
  4048.                 SetCustomPalette(!gInBackground);
  4049.             break;
  4050.  
  4051.         case rnmn_ID:                /* Render Menu */
  4052.             switch(theItem)
  4053.             {
  4054.                 case rnmn_options:                             /* Change options */
  4055.                         if (gSrcWind_dirty)
  4056.                         {
  4057.                             if (DoFile(fmn_save))
  4058.                                 ChangeFilePrefs();
  4059.                         }
  4060.                         else
  4061.                             ChangeFilePrefs();
  4062.                         break;
  4063.                 case rnmn_render:                            /* Render */
  4064.                         if (gSrcWind_dirty)
  4065.                             if (DoFile(fmn_save))
  4066.                                 ;
  4067.                         gBeginRendering = true;
  4068.                         break;
  4069.  
  4070.                 case rnmn_pause:                            /* pause trace */
  4071.                         pause_it();
  4072.                         break;    
  4073.  
  4074.                 case rnmn_stop:                                /* Abort trace in progress? */
  4075.                         ask_about_stop();
  4076.                         break;        
  4077.  
  4078.                 case rnmn_autosave:
  4079.                         gAutoSave = !gAutoSave;
  4080.                         break;
  4081.  
  4082.                 case rnmn_shutdown:
  4083.                         gAutoShutdown = !gAutoShutdown;
  4084.                         // display auto shutdown warning dialog
  4085.                         if (gDoingRender && gAutoShutdown)
  4086.                             (void)displayDialog(148, NULL, 0, ewcDoCentering, eSameAsPassedWindow); // power off warning
  4087.                         break;
  4088.             }
  4089.             break;
  4090.  
  4091.         case psmn_ID:                /* Processing Menu */
  4092.             switch (theItem)
  4093.             {
  4094.                 case psmn_border:
  4095.                     draw_border();
  4096.                     break;
  4097.  
  4098.                 case psmn_darken:
  4099.                     darken_image();
  4100.                     break;
  4101.  
  4102.                 case psmn_lighten:
  4103.                     lighten_image();
  4104.                     break;
  4105.  
  4106.                 case psmn_reduceC:
  4107.                     reduce_contrast();
  4108.                     break;
  4109.  
  4110.                 case psmn_increaseC:
  4111.                     increase_contrast();
  4112.                     break;
  4113.  
  4114.                 case psmn_invert:
  4115.                     invert_image();
  4116.                     break;
  4117.  
  4118.                 case psmn_revert:
  4119.                     revert_image();
  4120.                     break;
  4121.             }
  4122.             break;
  4123.  
  4124.         case wndmn_ID:                 /* Windows menu */
  4125.             switch (theItem)
  4126.             {
  4127.                 case 1: if (gp2wWindow)
  4128.                         {
  4129.                             SelectWindow((WindowPtr)gp2wWindow);
  4130.                         }
  4131.                         break;
  4132.  
  4133.                 case 2: if ((gSrcWind_Window) && (gSrcWind_visible))
  4134.                         {
  4135.                             SelectWindow(gSrcWind_Window);
  4136.                         }
  4137.                         break;
  4138.  
  4139.                 case 3: if (((WindowPeek)gImageWindowPtr)->visible)
  4140.                         {
  4141.                             SelectWindow(gImageWindowPtr);
  4142.                         }
  4143.                         break;
  4144.             }
  4145.             break;
  4146.  
  4147.         default:
  4148.             if ((theMenu >= macmn_sub_ID) && (theMenu <= macmn_sub_ID+NUM_MACRO_MENUS-1))
  4149.             {
  4150.                 HandleTemplateMenu(theMenu, theItem);
  4151.                 AdjustText();
  4152.             }
  4153.             break;
  4154.     }
  4155.  
  4156.     HiliteMenu(0);
  4157.  
  4158. } // DoCommand
  4159.  
  4160.  
  4161.  
  4162. // ---------------------------------------------------------------------
  4163. // Handle mouse down in windows or menus
  4164. static void DoMouseDown(void)
  4165. {
  4166.     short            code;
  4167.     WindowPtr        whichWindow;
  4168.     Rect            theWindowPos;    
  4169.  
  4170.     code = FindWindow(gTheEvent.where, &whichWindow);
  4171.     if (whichWindow == gSrcWind_Window)
  4172.     {
  4173.         DoEditMouseDown (code, whichWindow, &gTheEvent);
  4174.     }
  4175.     else
  4176.     {
  4177.         switch (code)
  4178.         {
  4179.             case inMenuBar:
  4180.                 SetCursor(&qd.arrow);
  4181.                 AdjustMenus();
  4182.                 DoCommand(MenuSelect(gTheEvent.where));
  4183.                 break;
  4184.  
  4185.             case inSysWindow:
  4186.                 SystemClick(&gTheEvent, whichWindow);
  4187.                 break;
  4188.  
  4189.             case inGoAway:
  4190.                 // neither Image nor Status have a close box, and the
  4191.                 // Source window's close is handled in DoEditMouseDown()
  4192.                 if (TrackGoAway(whichWindow, gTheEvent.where))
  4193.                     ;
  4194.                 break;
  4195.  
  4196.             case inGrow:
  4197.                 if ((whichWindow == (WindowPtr)gp2wWindow) && (gp2wWindow))
  4198.                 { // Status Window
  4199.                     p2w_DoGrow(gp2wWindow, &gTheEvent);
  4200.                     GetGlobalWindowRect((WindowPtr)gp2wWindow, &theWindowPos);
  4201.                     (**gFilePrefs_h).statWind_pos = theWindowPos;
  4202.                     // also remember this as default for next time
  4203.                     (**gDefltFilePrefs_h).statWind_pos = theWindowPos;
  4204.                 }
  4205.                 else if ((whichWindow == gImageWindowPtr) && (gImageWindowPtr))
  4206.                 { // Image Window
  4207.                     DoGrowImageWindow(gImageWindowPtr, gTheEvent.where);
  4208.                     GetGlobalWindowRect(gImageWindowPtr, &theWindowPos);
  4209.                     (**gFilePrefs_h).imageWind_pos = theWindowPos;
  4210. // Uncomment the next line to keep updating the default
  4211. // image wind position, not a good idea, IMHO.
  4212. /*
  4213.                     // also remember this as default for next time
  4214.                     (**gDefltFilePrefs_h).imageWind_pos = theWindowPos;
  4215. */
  4216.                 }
  4217.                 break;
  4218.  
  4219.             case inZoomIn:
  4220.             case inZoomOut:
  4221.                 SelectWindow(whichWindow);
  4222.                 if (TrackBox(whichWindow, gTheEvent.where, code))
  4223.                 {
  4224.                     if ((whichWindow == (WindowPtr)gp2wWindow) && (gp2wWindow))
  4225.                         p2w_DoZoom(gp2wWindow, code);
  4226.                     else if ((whichWindow == gImageWindowPtr) && (gImageWindowPtr))
  4227.                         ; // none
  4228.                 }
  4229.                 break;
  4230.  
  4231.             case inDrag:
  4232.                 SelectWindow(whichWindow);
  4233.                 DragWindow(whichWindow, gTheEvent.where, &gDragBounds);
  4234.                 GetGlobalWindowRect(whichWindow, &theWindowPos);
  4235.                 if ((whichWindow == (WindowPtr)gp2wWindow) && (gp2wWindow))
  4236.                 { // Status window
  4237.                     (**gFilePrefs_h).statWind_pos = theWindowPos;
  4238.                     // also remember this as default for next time
  4239.                     (**gDefltFilePrefs_h).statWind_pos = theWindowPos;
  4240.                 }
  4241.                 else if ((whichWindow == gImageWindowPtr) && (gImageWindowPtr))
  4242.                 { // Image Window
  4243.                     (**gFilePrefs_h).imageWind_pos = theWindowPos;
  4244. // Uncomment the next line to keep updating the default
  4245. // image wind position, not a good idea, IMHO.
  4246. /*
  4247.                     // also remember this as default for next time
  4248.                     (**gDefltFilePrefs_h).imageWind_pos = theWindowPos;
  4249. */
  4250.                 }
  4251.                 break;
  4252.  
  4253.             case inContent:
  4254.                 if (whichWindow != FrontWindow())
  4255.                     SelectWindow(whichWindow);
  4256.                 else
  4257.                 {
  4258.                     if ((whichWindow == (WindowPtr)gp2wWindow) && (gp2wWindow))
  4259.                         p2w_DoContentClick(gp2wWindow, &gTheEvent);
  4260.                     else
  4261.                     if (whichWindow == gImageWindowPtr)
  4262.                     {
  4263.                         SetPort(whichWindow);
  4264.                         GlobalToLocal(&gTheEvent.where);
  4265.                         // perform marquee dragging in here!
  4266.                     }
  4267.                 }
  4268.                 break;
  4269.         }
  4270.     }
  4271. } // DoMouseDown
  4272.  
  4273.  
  4274.  
  4275. // ---------------------------------------------------------------------
  4276. // Handle key downs
  4277. static void DoKeyDown(void)
  4278. {
  4279.     char    theChar, theVirtualCode;
  4280.  
  4281.     theChar = gTheEvent.message & charCodeMask;
  4282.     theVirtualCode = (gTheEvent.message & keyCodeMask) >> 8;
  4283.  
  4284.     if (gTheEvent.modifiers & cmdKey)
  4285.     {
  4286.         AdjustMenus();
  4287.         DoCommand(MenuKey(theChar));
  4288.     }
  4289.     else
  4290.     {
  4291.         if (FrontWindow() == gSrcWind_Window)
  4292.         {
  4293.             switch (theVirtualCode)
  4294.             {
  4295.                 case 0x33:                /* delete */
  4296.                     if ((**gSrcWind_TEH).selStart != (**gSrcWind_TEH).selEnd)
  4297.                     {
  4298.                         support_undo("Delete", TRUE);
  4299.                         TEDelete(gSrcWind_TEH);    /* delete a range */
  4300.                     }
  4301.                     else
  4302.                     {
  4303.                         support_undo_key();
  4304.                         TEKey(theChar, gSrcWind_TEH); /* delete char */
  4305.                     }
  4306.                     gSrcWind_dirty = 1;
  4307.                     AdjustText();
  4308.                     break;
  4309.  
  4310.                 case 0x73:                /* HOME */
  4311.                     undo_key_copied = 0;
  4312.                     SetCtlValue(gSrcWind_VScroll, 0);
  4313.                     AdjustText();
  4314.                     break;
  4315.  
  4316.                 case 0x77:                /* END */
  4317.                     undo_key_copied = 0;
  4318.                     SetCtlValue(gSrcWind_VScroll, (**gSrcWind_TEH).teLength);
  4319.                     AdjustText();
  4320.                     break;
  4321.  
  4322.                 case 0x74:                /* PAGE UP */
  4323.                     undo_key_copied = 0;
  4324.                     ScrollProc(gSrcWind_VScroll, inPageUp);
  4325.                     AdjustText();
  4326.                     break;
  4327.  
  4328.                 case 0x79:                /* PAGE DOWN */
  4329.                     undo_key_copied = 0;
  4330.                     ScrollProc(gSrcWind_VScroll, inPageDown);
  4331.                     AdjustText();
  4332.                     break;
  4333.  
  4334.                 case 0x7A:                /* UNDO (F1) */
  4335.                     undo_text();
  4336.                     break;
  4337.  
  4338.                 case 0x78:                /* CUT (F2) */
  4339.                     support_undo("Cut", TRUE);
  4340.                     TECut(gSrcWind_TEH);
  4341.                     AdjustText();
  4342.                     gSrcWind_dirty = 1;
  4343.                     break;
  4344.  
  4345.                 case 0x63:                /* COPY (F3) */
  4346.                     TECopy(gSrcWind_TEH);
  4347.                     break;
  4348.  
  4349.                 case 0x76:                /* PASTE (F4) */
  4350.                     support_undo("Paste", TRUE);
  4351.                     TEPaste(gSrcWind_TEH);
  4352.                     AdjustText();
  4353.                     gSrcWind_dirty = 1;
  4354.                     break;
  4355.                 
  4356.                 case 0x75:                /* del >x> */
  4357.                     if ((**gSrcWind_TEH).selStart != (**gSrcWind_TEH).selEnd)
  4358.                     {
  4359.                         support_undo("Delete", TRUE);
  4360.                         TEDelete(gSrcWind_TEH);
  4361.                         AdjustText();
  4362.                     }
  4363.                     else
  4364.                     {   /* cursor-right then delete */
  4365.                         support_undo_key();
  4366.                         TEKey(0x1D, gSrcWind_TEH); 
  4367.                         TEKey(0x08, gSrcWind_TEH);
  4368.                     }
  4369.                     gSrcWind_dirty = 1;
  4370.                     break;
  4371.  
  4372.                 case 0x1C:                /* Cursor keys, don't dirty the buffer or require undo */
  4373.                 case 0x1D:
  4374.                 case 0x1E:
  4375.                 case 0x1F:
  4376.                 case 0x7B:    /* arrow keys? */
  4377.                 case 0x7C:
  4378.                 case 0x7D:
  4379.                 case 0x7E:
  4380.                     undo_key_copied = 0;
  4381.                     TEKey(theChar, gSrcWind_TEH);
  4382.                     ShowSelect();
  4383.                     break;
  4384.  
  4385.                 default:                /* all other keys */
  4386.                     support_undo_key();
  4387.                     TEKey(theChar, gSrcWind_TEH);
  4388.                     gSrcWind_dirty = 1;
  4389.                     ShowSelect();
  4390.             }
  4391.         }
  4392.     }            
  4393. } // DoKeyDown
  4394.  
  4395.  
  4396.  
  4397. // ---------------------------------------------------------------------
  4398. // Handle disk inserted events (format uninit. disks if needed)
  4399. static void DoDiskEvt(EventRecord * pTheEventPtr)
  4400. {
  4401.     OSErr    anError;
  4402.     Point    aPoint;
  4403.  
  4404.     if (HiWord(pTheEventPtr->message) != noErr)
  4405.     {    // prompt to format it
  4406.         GetBestDialogPos(&aPoint);
  4407.         anError = DIBadMount(aPoint, pTheEventPtr->message);
  4408.     }
  4409. } // DoDiskEvt
  4410.  
  4411.  
  4412.  
  4413. // ---------------------------------------------------------------------
  4414. // Handle window update events
  4415. static void DoUpdateEvt(void)
  4416. {
  4417.     WindowPtr    wnd;
  4418.     
  4419.     wnd = (WindowPtr) gTheEvent.message;
  4420.     if ((wnd == gSrcWind_Window) && gSrcWind_Window)
  4421.         UpdateWindow (wnd);
  4422.     else
  4423.     if ((wnd == (WindowPtr) gp2wWindow) && gp2wWindow)
  4424.     {
  4425.         p2w_DoUpdate(gp2wWindow);
  4426.     }
  4427.     else
  4428.     {    /* update the image window */
  4429.         if ((wnd == gImageWindowPtr) && gImageWindowPtr)
  4430.         {
  4431.             UpdateImageWindow();
  4432.         }
  4433.     }
  4434. } // DoUpdateEvt
  4435.  
  4436.  
  4437.  
  4438. // ---------------------------------------------------------------------
  4439. // Handle window activate events
  4440. static void DoActivateEvt(void)
  4441. {
  4442.     HandleActivate((WindowPtr) gTheEvent.message, gTheEvent.modifiers & 1);
  4443. } // DoActivateEvt
  4444.  
  4445.  
  4446.  
  4447. // ---------------------------------------------------------------------
  4448. // Handle OS Events (Suspend/resume)
  4449. static void DoOSEvt(void)
  4450. {
  4451.     if (gTheEvent.message >> 24 == 1)
  4452.     {
  4453.         if (gTheEvent.message & 1)
  4454.         {
  4455.             gInBackground = false;
  4456.             HandleActivate((WindowPtr) gTheEvent.message, 1);
  4457.         }
  4458.         else
  4459.         {
  4460.             gInBackground = true;
  4461.             HandleActivate((WindowPtr) gTheEvent.message, 0);
  4462.         }
  4463.         SetCursor(&qd.arrow);
  4464.     }
  4465. } // DoOSEvt
  4466.  
  4467.  
  4468.  
  4469. // ---------------------------------------------------------------------
  4470. // Handle any high level events (AppleEvents currently)
  4471. static void DoHighLevelEvt(void)
  4472. {
  4473.     short i;
  4474.  
  4475.     if ((**gPrefs2Use_h).progress >= kProgDebug)
  4476.         printf("-d HighLvlEvtClass='%4s'\n", &gTheEvent.message);
  4477.     if (gTheEvent.message == kCoreEventClass)
  4478.         i = AEProcessAppleEvent(&gTheEvent);
  4479.     /* AppleEvents are currently the only supported high level events */
  4480. } // DoHighLevelEvt
  4481.  
  4482.  
  4483.  
  4484. // ---------------------------------------------------------------------
  4485. // Do everything you ever need to do in the guts of a Mac event loop
  4486. static void CheckForEvents(void)
  4487. {
  4488.     FSSpec    aFile;
  4489.  
  4490.     // Stuff that only gets done if we're in front.
  4491.     if (!gInBackground)
  4492.     {
  4493.         if (gSrcWind_Window)
  4494.         {
  4495.             SetPort(gSrcWind_Window);
  4496.             MaintainCursor();
  4497.             if (gSrcWind_TEH)
  4498.                 TEIdle(gSrcWind_TEH);
  4499.         }
  4500.     }
  4501.  
  4502.     // Check for timeout on startup message.  Remove the dialog after timeout.
  4503.     if (gSplashScreen) // if screen still up..
  4504.         if    ((gSplashStartTicks + 8*60L) < TICKS)    // timeout after 8 seconds
  4505.         {
  4506.             KillSplashScreen();
  4507.         }
  4508.  
  4509.     // take care of next drag-n-dropped file
  4510.     if (!gDoingBatchODOCs)
  4511.         if (FileQ_NumItems() > 0)
  4512.             if (FileQ_Get(&aFile))
  4513.                 BatchProcessOneFile(&aFile);
  4514.  
  4515.     // get next event
  4516.     if (gDoingRender)
  4517.     {
  4518.         // Rendering, don't go away for long
  4519.         WaitNextEvent(everyEvent, &gTheEvent, gWNEReleaseTicks, NULL);
  4520.     }
  4521.     else
  4522.     {
  4523.         // idle, let other apps breathe more
  4524.         WaitNextEvent(everyEvent, &gTheEvent, 30, NULL);
  4525.     }
  4526.  
  4527.     // handle the event
  4528.     switch (gTheEvent.what)
  4529.     {
  4530.         case mouseDown:        
  4531.                     // If the startup screen is still up, kill it
  4532.                     if (gSplashScreen)
  4533.                         KillSplashScreen();
  4534.                     DoMouseDown();
  4535.                     break;
  4536.  
  4537.         case keyDown:
  4538.         case autoKey: 
  4539.                     // If the startup screen is still up, kill it
  4540.                     if (gSplashScreen)
  4541.                         KillSplashScreen();
  4542.                     DoKeyDown(); 
  4543.                     break;
  4544.  
  4545.         case diskEvt:
  4546.                     DoDiskEvt(&gTheEvent);
  4547.                     break;
  4548.  
  4549.         case updateEvt:
  4550.                     DoUpdateEvt();
  4551.                     break;
  4552.  
  4553.         case activateEvt:
  4554.                     DoActivateEvt();
  4555.                     break;
  4556.  
  4557.         case osEvt:    // suspend/resume, mousemoved..
  4558.                     DoOSEvt();
  4559.                     break;
  4560.  
  4561.         case kHighLevelEvent:    // AppleEvents
  4562.                     DoHighLevelEvt();
  4563.                     break;
  4564.  
  4565.         case nullEvent:
  4566.         default:
  4567.                     // DoNullEvt();
  4568.                     break;
  4569.     }
  4570. } // CheckForEvents
  4571.  
  4572.  
  4573.  
  4574. // ---------------------------------------------------------------------
  4575. // Called from rendering engine, allows Mac code to breathe while the
  4576. // renderer is parsing and rendering.  This keeps menus working..
  4577. // doImmediate if true will always breathe, otherwise it breathes every N calls
  4578. void Cooperate(int doImmediate)
  4579. {
  4580.     if ( doImmediate || (TICKS > (gPrevTickCount+((gCpuHogginess-1)<<2))) )
  4581.     {
  4582.         // Update the clock before other applications
  4583.         // have breathed, so our time slices are more equally spaced
  4584.         gPrevTickCount = TICKS;
  4585.  
  4586.         // Now let other apps breathe
  4587.         CheckForEvents();
  4588.     }
  4589. } // Cooperate
  4590.  
  4591.  
  4592. // Silly Wabbit, programming trix are for twids!
  4593. // MPW C and Symantec C define lomem globals ever-so-slightly
  4594. // differently, so we have to special case them here.
  4595.  
  4596. #if defined(THINK_C)
  4597. #define CURDIRSTORE_LOC        (CurDirStore)
  4598. #define SFSAVEDISK_LOC        (SFSaveDisk)
  4599. #else
  4600. #define CURDIRSTORE_LOC        (*(long int*)CurDirStore)
  4601. #define SFSAVEDISK_LOC        (*(short int*)SFSaveDisk)
  4602. #endif
  4603.  
  4604. // ---------------------------------------------------------------------
  4605. // Set default SF Getfile dialog initial directory
  4606. static void SetSFCurrent(FSSpecPtr pTheFSFilePtr)
  4607. {
  4608.     OSErr        anError = noErr;
  4609.  
  4610.     // Standard File wants the dirID and the negated vRefnum..
  4611.     // so give it to 'em that way
  4612. #if defined(__powerc)
  4613.     /* do it the new PowerPC way */
  4614.     LMSetCurDirStore(pTheFSFilePtr->parID);
  4615.     LMSetSFSaveDisk(-(pTheFSFilePtr->vRefNum));
  4616. #else
  4617.     CURDIRSTORE_LOC        = pTheFSFilePtr->parID;
  4618.     SFSAVEDISK_LOC        = -(pTheFSFilePtr->vRefNum);
  4619. #endif // __powerc
  4620.  
  4621. } // SetSFCurrent
  4622.  
  4623.  
  4624.  
  4625. // ---------------------------------------------------------------------
  4626. // Returns TRUE if all required AE parms were extracted OK
  4627. static OSErr GotRequiredAEParams(AppleEvent    *theAppleEvent)
  4628. {
  4629.     DescType    typeCode;
  4630.     Size        actualSize;
  4631.     OSErr        err;
  4632.  
  4633.     err = AEGetAttributePtr(theAppleEvent, keyMissedKeywordAttr, typeWildCard,
  4634.                             &typeCode, NULL, 0, &actualSize);    /* NULL ok here; need only function result */
  4635.     if (err == errAEDescNotFound)
  4636.         // we got all the required params: all is ok
  4637.         return noErr;
  4638.     else if (err == noErr)
  4639.         // found one left behind: error!
  4640.         return errAEEventNotHandled;
  4641.     else
  4642.         // some other oddity
  4643.         return err;
  4644. } // GotRequiredAEParams
  4645.  
  4646.  
  4647.  
  4648. // ---------------------------------------------------------------------
  4649. // AE Handler - Oapp - If app run with no documents
  4650. static pascal OSErr HandleAEOapp(AEDescList *aevt, AEDescList *reply, long refCon)
  4651. {
  4652. #pragma unused (reply,refCon)
  4653.     OSErr    anError;
  4654.  
  4655.     /* We don't normally expect any parms, but check in case the client requires any */
  4656.     anError = GotRequiredAEParams(aevt);
  4657.  
  4658.     // if user hasn't already opened a window, open a new untitled window
  4659.     if (!anError && (gSrcWind_VRefNum == 0))
  4660.         DoFile_New();
  4661.  
  4662.     return anError;
  4663. } // HandleAEOApp
  4664.  
  4665.  
  4666.  
  4667. // ---------------------------------------------------------------------
  4668. // AE Handler - Odoc - If app run with some documents, or if docs are
  4669. // dropped onto app after it is running
  4670. static pascal OSErr HandleAEOdoc(AEDescList *aevt, AEDescList *reply, long refCon)
  4671. {
  4672. #pragma unused (reply,refCon)
  4673.     OSErr        anError;
  4674.     long        numFiles;
  4675.     long        index;
  4676.     long        actualSize;
  4677.     DescType    actualType;
  4678.     FInfo        theFileInfo;
  4679.     AEDesc        fileListDesc;
  4680.     AEKeyword    actualKeyword;
  4681.     FSSpec        theFSSpec;
  4682.     char        theFname[64];
  4683.                         
  4684.     /* The "odoc" and "pdoc" messages contain a list of aliases as the direct paramater.    */
  4685.     /* This means that we'll need to extract the list, count the list's elements, and        */
  4686.     /* then process each file in turn.    Return any errors to the client.                    */
  4687.  
  4688.     /* Extract the list of aliases into fileListDesc */
  4689.     anError = AEGetParamDesc(aevt, keyDirectObject, typeAEList, &fileListDesc);
  4690.  
  4691.     /* Make sure that's all we're supposed to do */
  4692.     if (!anError)
  4693.         anError = GotRequiredAEParams(aevt);
  4694.         
  4695.     /* Count the list elements */
  4696.     if (!anError)
  4697.         anError = AECountItems(&fileListDesc, &numFiles);
  4698.  
  4699.     /* now get each file from the list and process it. */
  4700.     /* Even though the event contains a list of aliases, the Apple Event Manager */
  4701.     /* will convert each alias to an FSSpec if we ask it to. */
  4702.     for (index = 1; (index <= numFiles) && !anError; index++)
  4703.     {
  4704.         /* Pull the Nth file out of the aevt list */
  4705.         anError = AEGetNthPtr( &fileListDesc, index, typeFSS, &actualKeyword,
  4706.                             &actualType, (Ptr)&theFSSpec, sizeof(theFSSpec), &actualSize);
  4707.  
  4708.         // C version of filename
  4709.         BlockMove(theFSSpec.name, theFname, theFSSpec.name[0]+1);
  4710.         p2cstr((StringPtr)theFname);
  4711.  
  4712.         if ((**gDefltFilePrefs_h).progress >= kProgDebug)
  4713.         {
  4714.             printf("-d ODOC='%s'\n", theFname);
  4715.         }
  4716.  
  4717.         // better be a text file..
  4718.         // Note: We're in an AE Handler, so guaranteed to be System 7, so ok to call:
  4719.         FSpGetFInfo(&theFSSpec, &theFileInfo);
  4720.         if (theFileInfo.fdType != 'TEXT')
  4721.         {
  4722.             (void)displayDialog(kdlog_CantOpenNonText,
  4723.                             theFname, 0, ewcDoCentering, eSameAsPassedWindow);
  4724.             anError = 1;
  4725.             break; // drop out of for loop..
  4726.         }
  4727.  
  4728.         /* Open the File here */
  4729.         if (!anError)
  4730.         {
  4731.             // Use this file to set anchor for any future SFGetFile opens...
  4732.             // in other words, if you drop one or more files onto POV-Ray, then
  4733.             // the next time you do a File-Open, the standard file dialog will
  4734.             // open at the directory of your dropped file, not the app directory.
  4735.             // (You're welcome Anton! [esp] :-)
  4736.             if (index == 1)
  4737.                 SetSFCurrent(&theFSSpec);
  4738.  
  4739.             if ((**gDefltFilePrefs_h).progress >= kProgDebug)
  4740.             {
  4741.                 printf("-d  NumFiles=%d,  DoingBatch=%d,  DoingRender=%d\n",
  4742.                         (int)numFiles, gDoingBatchODOCs, gDoingRender);
  4743.             }
  4744.     
  4745.             if (gDoingBatchODOCs)
  4746.             {    // already queued some, queue these too
  4747.                 FileQ_Put(&theFSSpec);
  4748.             }
  4749.             else
  4750.             {
  4751.                 // Don't open it if a file is already open and dirty (unsaved)
  4752.                 if (gSrcWind_dirty)
  4753.                 {
  4754.                     (void)displayDialog(kdlog_CantOpenOverDirty,
  4755.                                     NULL, 0, ewcDoCentering, eSameAsPassedWindow);
  4756.                     break; // no more files..
  4757.                 }
  4758.                 else
  4759.                 {    // ok to add
  4760.                     if ((numFiles == 1) && !gDoingRender)
  4761.                     {
  4762.                         // Simple case, just one file to open, just open it and wait
  4763.                         OpenTextFile(theFSSpec.name, theFSSpec.vRefNum, theFSSpec.parID, true/*UseDirID*/);
  4764.                     }
  4765.                     else
  4766.                     {
  4767.                         // mult. files dropped, or already rendering one.
  4768.                         // put each file in a queue for later batch processing
  4769.                         FileQ_Put(&theFSSpec);
  4770.  
  4771.                         // This is a sly way to tell DoRendering() to save the current
  4772.                         // file being rendered automatically, before opening the next
  4773.                         // file in the queue.
  4774.                         if (gDoingRender)
  4775.                             gDoingBatchODOCs = true;
  4776.                     }
  4777.                 }    // else ok to add
  4778.             }
  4779.         }    // if !error
  4780.     }    // for
  4781.  
  4782.     /* All done with the AE list, throw it away */
  4783.     if (!anError)
  4784.         anError = AEDisposeDesc(&fileListDesc);
  4785.  
  4786.     return anError;
  4787. } // HandleAEOdoc
  4788.  
  4789.  
  4790.  
  4791. // ---------------------------------------------------------------------
  4792. // AE Handler - Quit - Ask app to quit cleanly
  4793. static pascal OSErr HandleAEQuit(AEDescList *aevt, AEDescList *reply, long refCon)
  4794. {
  4795. #pragma unused (reply,refCon)
  4796.  
  4797.     OSErr    anError;
  4798.  
  4799.     /* We don't normally expect any parms, but check in case the client requires any */
  4800.     anError = GotRequiredAEParams(aevt);
  4801.  
  4802.     Stop_Flag = gQuit = TRUE;
  4803.     return anError;
  4804. } // HandleAEQuit
  4805.  
  4806.  
  4807.  
  4808. // ---------------------------------------------------------------------
  4809. // Install our AppleEvent handlers (above) so they can be called automatically
  4810. // by AEProcessAppleEvent()
  4811. static void InstallAppleEvents(void)
  4812. {
  4813.  
  4814. #if defined(__powerc)
  4815.     (void)AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, 
  4816.                         (EventHandlerUPP)&gAEOAppRD, 0, false);
  4817.     (void)AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,   
  4818.                         (EventHandlerUPP)&gAEODocRD, 0, false);
  4819.     /* handle "Print" as Open */
  4820.     (void)AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,  
  4821.                         (EventHandlerUPP)&gAEODocRD, 0, false);
  4822.     (void)AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, 
  4823.                         (EventHandlerUPP)&gAEQuitRD, 0, false);
  4824. #else
  4825.     (void)AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, 
  4826.                         (EventHandlerProcPtr)HandleAEOapp, 0, false);
  4827.     (void)AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,   
  4828.                         (EventHandlerProcPtr)HandleAEOdoc, 0, false);
  4829.     /* handle "Print" as Open */
  4830.     (void)AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,  
  4831.                         (EventHandlerProcPtr)HandleAEOdoc, 0, false);
  4832.     (void)AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, 
  4833.                         (EventHandlerProcPtr)HandleAEQuit, 0, false);
  4834. #endif //__powerc
  4835. } // InstallAppleEvents
  4836.  
  4837.  
  4838.  
  4839. // ---------------------------------------------------------------------
  4840. // Do any necessary cleanup prior to exiting
  4841. void exit_handler(void)
  4842. {
  4843.     dispose_virtual();        /* close virtual file */
  4844.  
  4845.     KillImageWindow();
  4846.  
  4847.     KillOffscreen();
  4848.  
  4849.     FileQ_d();    // Tear down ODOC File Queue
  4850.  
  4851.     KillTemplateMenu();
  4852.  
  4853.     if (gSrcWind_VRefNum != 0)    // if there is a file open..
  4854.     {
  4855.         WriteFilePrefs();
  4856.     }
  4857.  
  4858.     if (gAppPrefs_h)
  4859.         WriteAppPrefs();
  4860.  
  4861.     if (gtheSCComponent != NULL)
  4862.     {
  4863.         CloseComponent(gtheSCComponent);
  4864.         gtheSCComponent = NULL;
  4865.     }
  4866.  
  4867.     if (gp2wWindow)
  4868.     {
  4869.         p2w_DisposeWindow(gp2wWindow);
  4870.         gp2wWindow = NULL;
  4871.     }
  4872.     p2w_Terminate();
  4873.  
  4874.     gQuit = 1;    // must do this, Think C calls unexpected_exit (again) INSIDE ExitToShell!
  4875. } // exit_handler
  4876.  
  4877.  
  4878.  
  4879. // ---------------------------------------------------------------------
  4880. // Called if unexpectedly aborting
  4881. static void unexpected_exit(void)
  4882. {
  4883.     // we are exiting within an error condition at this point...
  4884.     if (gQuit == 0)
  4885.     {
  4886.         if (gAppPrefs_h)
  4887.         {    
  4888.             DisposeHandle((Handle) gAppPrefs_h);
  4889.             gAppPrefs_h = NULL;    
  4890.         }    
  4891.         // fatal error, exiting
  4892.         (void)displayDialog(132, NULL, 0, ewcDoCentering, eMainDevice);
  4893.         exit_handler();
  4894.         ExitToShell();
  4895.     }
  4896. } // unexpected_exit
  4897.  
  4898.  
  4899.  
  4900. // ---------------------------------------------------------------------
  4901. // Set initial configuration flags
  4902. static Boolean CheckGestaltBit(unsigned long gestaltResponse, short gestaltBit)
  4903. {
  4904.     return( (gestaltResponse & (1<<gestaltBit) ) != 0);
  4905. } // CheckGestaltBit
  4906.  
  4907.  
  4908.  
  4909. // ---------------------------------------------------------------------
  4910. // Set initial configuration flags
  4911. static void CheckConfiguration(void)
  4912. {
  4913.     long        gestaltResponse;
  4914.     char        *errStr;    
  4915.  
  4916.     errStr = NULL;    
  4917.  
  4918.     // Check system version stuff
  4919.     gHasSys70 = false;
  4920.     if (Gestalt(gestaltSystemVersion, &gestaltResponse) == noErr)
  4921.     {
  4922.         gHasSys70 = (gestaltResponse >= 0x0700);
  4923.         if ((gestaltResponse < 0x0604) && (errStr == NULL))
  4924.             errStr = "You do not have System 6.0.4 or better.";    
  4925.     }
  4926.  
  4927.     // Check CPU stuff
  4928. #if defined (NEEDS_68020)
  4929.     if (Gestalt(gestaltProcessorType, &gestaltResponse) == noErr)
  4930.     {
  4931.         if ((gestaltResponse < gestalt68020)     && (errStr == NULL))
  4932.             errStr = "You do not have a 68020 or better CPU.";    
  4933.     }
  4934. #endif // NEEDS_68020
  4935.  
  4936.     // Check FPU stuff
  4937.     if (Gestalt(gestaltFPUType, &gestaltResponse) == noErr)
  4938.     {
  4939. #if defined (NEEDS_FPU)
  4940.         // If this was compiled to REQUIRE FPU, get error if no FPU installed
  4941.         if ((gestaltResponse == gestaltNoFPU) && (errStr == NULL))
  4942.             errStr = "You do not have a Floating Point Unit.";
  4943. #else
  4944.         // if compiled to not need FPU, give warning if running on FPU machine
  4945.         if (gestaltResponse != gestaltNoFPU)
  4946.             displayDialog(kdlog_UseFPUVersion, NULL, 0, ewcDoCentering, eMainDevice);
  4947. #endif // NEEDS_FPU
  4948.     }
  4949.  
  4950.     // Check Quickdraw stuff
  4951.     gHas32BitQD = false;
  4952.     gHasPictUtils = false;
  4953.     if (Gestalt(gestaltQuickdrawVersion, &gestaltResponse) == noErr)
  4954.     {
  4955.         gHas32BitQD = (gestaltResponse >= gestalt32BitQD);
  4956.         gHasPictUtils = (gestaltResponse >= gestalt32BitQD) && gHasSys70;
  4957. #if defined (NEEDS_32BITQD)
  4958.         if ((!gHas32BitQD)  && (errStr == NULL))
  4959.             errStr = "You do not have 32 Bit Quickdraw.";
  4960. #endif // NEEDS_32BITQD
  4961.     }
  4962.  
  4963.     // Check QuickTime version
  4964.     gHasQuickTime = false;
  4965.     gHasImageCompressionMgr = false;
  4966.     if (Gestalt(gestaltQuickTime, &gestaltResponse) == noErr)
  4967.     {
  4968.         gQTVersion = gestaltResponse;
  4969.         if (gQTVersion >= 0x01508000) // at least version 1.5 final
  4970.         {
  4971.             gHasQuickTime = true;
  4972.             // Check QuickTime Compression stuff
  4973.             if (Gestalt(gestaltCompressionMgr, &gestaltResponse) == noErr)
  4974.                 gHasImageCompressionMgr = CheckGestaltBit(gestaltResponse, 4);
  4975.         }
  4976.     }
  4977.  
  4978.     // Check AppleEvent stuff
  4979.     gHasAppleEvents = false;
  4980.     if (Gestalt(gestaltAppleEventsAttr, &gestaltResponse) == noErr)
  4981.         gHasAppleEvents = CheckGestaltBit(gestaltResponse, gestaltAppleEventsPresent);
  4982.  
  4983.     // Check popup mgr stuff
  4984.     gHasPopups = false;
  4985.     if (Gestalt(gestaltPopupAttr, &gestaltResponse) == noErr)
  4986.         gHasPopups = CheckGestaltBit(gestaltResponse, gestaltPopupPresent);
  4987.  
  4988.     // Show any initialization errors now
  4989.     if (errStr)    
  4990.     {    // insufficient hardware/software config..
  4991.         displayDialog(kdlog_ConfigFatalErr, errStr, 0, ewcDoCentering, eMainDevice);
  4992.         exit_handler();
  4993.         ExitToShell();
  4994.     }
  4995. } // CheckConfiguration
  4996.  
  4997.  
  4998.  
  4999. // ---------------------------------------------------------------------
  5000. // Read any special cursors to be used later
  5001. static void SetupCursors(void)
  5002. {
  5003.     CursHandle    hCurs;
  5004.     
  5005.     // Note: iBeamCursor & watchCursor are defined in ToolUtils.h
  5006.     hCurs = GetCursor(iBeamCursor);
  5007.     gEditCursor = **hCurs;
  5008.     hCurs = GetCursor(watchCursor);
  5009.     gWaitCursor = **hCurs;
  5010. } // SetupCursors
  5011.  
  5012.  
  5013.  
  5014. // ---------------------------------------------------------------------
  5015. // load all needed menus
  5016. static void SetupMenus()
  5017. {
  5018.     int    i;
  5019.  
  5020.     for (i = 0; i < num_of_menus; i++)
  5021.     {
  5022.         myMenus[i] = GetMenu(i + menu_offset);
  5023.         if (myMenus[i] == NULL)
  5024.         {
  5025.             (void)displayDialog(kdlog_GenericFatalErr, "Cannot get main menu resource", i, ewcDoCentering, eMainDevice);
  5026.             exit_handler();
  5027.         }
  5028.         else
  5029.         {
  5030.             if (i==0) // add DA list to Apple menu
  5031.                 AddResMenu(myMenus[apmn_ID - menu_offset], 'DRVR');
  5032.             InsertMenu(myMenus[i], 0);
  5033.         }
  5034.     }
  5035.     for (i = 0; i < num_of_submenus; i++)
  5036.     {
  5037.         mySubMenus[i] = GetMenu(i + submenu_offset);
  5038.         if (mySubMenus[i] == NULL)
  5039.         {
  5040.             (void)displayDialog(kdlog_GenericFatalErr, "Cannot get sub-menu resource", i, ewcDoCentering, eMainDevice);
  5041.             exit_handler();
  5042.         }
  5043.         else
  5044.             InsertMenu(mySubMenus[i], -1);
  5045.     }
  5046.     DrawMenuBar();
  5047.     
  5048.     // disable menus until we are ready...
  5049.     DisableMenus();
  5050. } // SetupMenus
  5051.  
  5052.  
  5053.  
  5054. // ---------------------------------------------------------------------
  5055. // hello Mac world...
  5056. int main(void)
  5057. {
  5058.     long                stk_size;
  5059.     short                memTrax_Size;
  5060.     long                maxMallocListSize;
  5061.     app_config_hdl_t    app_config_h;
  5062.     int                    i,j;
  5063.     OSErr                anError;
  5064.     Rect                p2wRect;    
  5065.     PicHandle            scPicH = NULL;
  5066.  
  5067. #if defined(applec)
  5068.     UnloadSeg((Ptr) _DataInit);
  5069. #endif // applec
  5070.  
  5071.     AppRefNum = CurResFile();
  5072.  
  5073.     /* Allocate more memory for stack before doing much heap stuff! */
  5074.     app_config_h = (app_config_hdl_t)Get1Resource(kAppConfigRsrc, kAppConfigRsrcID);
  5075.     if (app_config_h)
  5076.     {
  5077.         // stackSize - # of bytes to grow the stack to (for recursion)
  5078.         // [10k < stk_size < 150k]
  5079.         stk_size = (**app_config_h).stackSize;
  5080.         if (stk_size <= 10000L)
  5081.             stk_size = 10000L;
  5082.         else if (stk_size > 150000L)
  5083.             stk_size = 150000L;
  5084.  
  5085.         // memTrackingSize - percentage of free mem to use for malloc tracking
  5086.         // [0 < memTrax_Size < 100]
  5087.         memTrax_Size = (**app_config_h).memTrackingSize;
  5088.         if (memTrax_Size < 0)
  5089.             memTrax_Size = 0;
  5090.         else if (memTrax_Size > 99)
  5091.             memTrax_Size = 99;
  5092.         // all done with this
  5093.         ReleaseResource((Handle)app_config_h);
  5094.     }
  5095.     else
  5096.     { // set to default values
  5097.         stk_size = DEFAULT_STACK_SIZE;
  5098.         memTrax_Size = 10; // 10% avail mem
  5099.     }
  5100.     SetApplLimit(GetApplLimit() - stk_size);
  5101.     MaxApplZone();
  5102.  
  5103.     /* give us some master pointer blocks ahead of time, to reduce later memfrag */
  5104.     // base the # needed on the % mallocs they track
  5105.     j = 20*memTrax_Size;
  5106.     for (i=0; i<j; i++)
  5107.         MoreMasters();
  5108.  
  5109.     /* Initialize toolbox managers. */
  5110.     InitGraf(&qd.thePort);
  5111.     InitFonts();
  5112.     InitWindows();
  5113.     InitMenus();
  5114.     TEInit();
  5115.     InitDialogs(NULL);
  5116.     InitCursor();
  5117.     SetupCursors();
  5118.     SetCursor(&gWaitCursor);
  5119.  
  5120.     /* Register an exit handler */
  5121.     atexit(unexpected_exit);
  5122.  
  5123.     /* Bring us to the front under MultiFinder */
  5124.     i=EventAvail(0, &gTheEvent);
  5125.     i=EventAvail(0, &gTheEvent);
  5126.     i=EventAvail(0, &gTheEvent);
  5127.  
  5128.     /* Check if the necessary hard- & software is present. */
  5129.     CheckConfiguration();
  5130.  
  5131.     // set up a full distribution message for display in splash screen and about box.
  5132.     gDistMessage = (StringPtr)NewPtr(256);
  5133.     strcpy((char*)gDistMessage, DISTRIBUTION_MESSAGE_1);
  5134.     strcat((char*)gDistMessage, " ");
  5135.     strcat((char*)gDistMessage, DISTRIBUTION_MESSAGE_2);
  5136.     strcat((char*)gDistMessage, " ");
  5137.     strcat((char*)gDistMessage, DISTRIBUTION_MESSAGE_3);
  5138.     c2pstr((char*)gDistMessage);
  5139.  
  5140.     /* create application prefs records */
  5141.     gAppPrefs_h = (app_prefs_hdl_t) NewHandle(sizeof(app_prefs_rec_t)); 
  5142.     MoveHHi((Handle) gAppPrefs_h);
  5143.     HLock((Handle) gAppPrefs_h);
  5144.  
  5145.     /* create default file settings record */
  5146.     gDefltFilePrefs_h = (file_prefs_hdl_t) NewHandle(sizeof(file_prefs_rec_t)); 
  5147.     MoveHHi((Handle) gDefltFilePrefs_h);
  5148.     HLock((Handle) gDefltFilePrefs_h);
  5149.  
  5150.     /* create file settings record */
  5151.     gFilePrefs_h = (file_prefs_hdl_t) NewHandle(sizeof(file_prefs_rec_t)); 
  5152.     MoveHHi((Handle) gFilePrefs_h);
  5153.     HLock((Handle) gFilePrefs_h);
  5154.  
  5155.     /* set up bounds for window dragging (multiple/big monitors) */
  5156.     SetRect(&gDragBounds, -32000, -32000, 32000, 32000);
  5157.  
  5158.     /* display splash screen early on, while app gets set up */
  5159.     CreateSplashScreen();
  5160.  
  5161.     /* See if the image compression manager (QuickTime to the Rest Of Us) is installed. */
  5162.     if (gHasImageCompressionMgr)
  5163.     {
  5164.         /* Install and open the standard compression dialog component. */
  5165. // the old way..
  5166. //        gtheSCComponent = OpenStdCompression();
  5167. // the better way
  5168.         gtheSCComponent = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
  5169.         if (gtheSCComponent)
  5170.         {
  5171.             /* Initial defaults for SC compression dialog. */    
  5172.             (void)SCGetInfo(gtheSCComponent, scSpatialSettingsType, &(**gDefltFilePrefs_h).sc_DialogParams);
  5173.             scPicH = GetPicture(kDemoPICTrsrcID);
  5174.             // pick a preview pict for initializing the SC defaults
  5175.             if (scPicH)
  5176.             {
  5177.                 // set default pict
  5178.                 (void)SCDefaultPictHandleSettings(gtheSCComponent, scPicH, false);
  5179.                 // get defaults the component set up
  5180.                 (void)SCSetTestImagePictHandle(gtheSCComponent, scPicH,
  5181.                                                 NULL, scPreferScalingAndCropping);
  5182.             }
  5183.         }
  5184.     }
  5185.  
  5186.     /* Set up application menus. */
  5187.     SetupMenus();
  5188.  
  5189.     /* Read global settings from prefs file */
  5190.     GetAppPrefs();
  5191.  
  5192.     // refresh splash screen in case previous dialogs walked on it
  5193. /*---
  5194. This creates an annoying refresh partway through startup EVERY TIME.  Instead,
  5195. we will live with the ONE TIME that the "updating prefs" dialog steps on the
  5196. splash screen, and leave it with an un-updated hole in it. [esp]
  5197. -bug reported 7/16/93 [ar]
  5198.     if (gSplashScreen)
  5199.     {
  5200.         SelectWindow(gSplashScreen);
  5201.         DrawDialog(gSplashScreen);
  5202.     }
  5203. ---*/
  5204.  
  5205.  
  5206.     *gSrcWind_FileName = '\0';
  5207.  
  5208.     // Set up the status output window
  5209.     anError = p2w_Init();
  5210.     if (!anError)
  5211.     {
  5212.         p2wRect = (**gDefltFilePrefs_h).statWind_pos;
  5213.         gp2wWindow = p2w_NewWindow(kWindID_p2w, &p2wRect, "\pPOV-Ray Status", true, monaco, 9, &anError);
  5214.     }
  5215.     if (anError)
  5216.     {
  5217.         (void)displayDialog(kdlog_P2W_INIT_ERROR, NULL, 0, ewcDoCentering, eMainDevice);
  5218.         exit_handler();
  5219.     }
  5220.  
  5221.     // has QuickTime, but not Image compression mgr (probably old QT version)
  5222.     // if debug mode, display some info to user
  5223.     if (((**gDefltFilePrefs_h).progress >= kProgDebug) && gHasQuickTime)
  5224.     {
  5225.         printf("-d QuickTimeVersion=0x%08lx, ImageCompressionExists=%d\n", gQTVersion, gHasImageCompressionMgr);
  5226.     }
  5227.  
  5228.     // set up template menu
  5229.     anError = InitTemplateMenu();
  5230.     if (anError)
  5231.     {
  5232.         // fatal error
  5233.         displayDialog(kdlog_GenericFatalErr, "Cannot create template submenus",
  5234.                     anError, ewcDoCentering, eMainDevice);
  5235.         exit_handler();
  5236.     }
  5237.  
  5238.     InitImageWindow();
  5239.  
  5240.     SetupPalettes();
  5241.  
  5242.     // Set up offscreen pixmap
  5243.     SetupOffscreen();
  5244.  
  5245.     // display stack size
  5246.     if ((**gDefltFilePrefs_h).progress >= kProgDebug)
  5247.     {
  5248.         printf("-d StackSize=%ldK\n", stk_size/1024);
  5249.     }
  5250.  
  5251.     // allocate malloc() garbage collection buffers
  5252.     // max entries = memTrax_Size % of avail memory (div 2 since there are 2 lists),
  5253.     // and 500 entries minimum.
  5254.     maxMallocListSize = (FreeMem() * (long)memTrax_Size) / (2L*100L) / (long)sizeof(Ptr);
  5255.     if ((**gDefltFilePrefs_h).progress >= kProgDebug)
  5256.     {
  5257.         printf("-d MemTrackBuffEntries=%ld, MemTrackBuffPercent=%d%%\n", maxMallocListSize, memTrax_Size);
  5258.     }
  5259.     anError = POV_init_memtracking(maxMallocListSize);
  5260.     if (anError)
  5261.     {
  5262.         // fatal error
  5263.         displayDialog(kdlog_GenericFatalErr,
  5264.                 "Cannot allocate memory for garbage collection",
  5265.                 maxMallocListSize, ewcDoCentering, eMainDevice);
  5266.         exit_handler();
  5267.     }
  5268.     POV_enable_memtracking(false);
  5269.  
  5270.     // init the fake argc/argv buffers
  5271.     InitArgs();
  5272.  
  5273.     // initialize the ODOC File Queue
  5274.     FileQ_c();
  5275.  
  5276.     init_undo_system();
  5277.     init_redo_system();
  5278.  
  5279.     if (gHasAppleEvents)
  5280.         InstallAppleEvents();
  5281.  
  5282.     gRenderedOK = true;
  5283.  
  5284.     /* Figure out how much (or little) time to give other processes (oink) */
  5285.     gCpuHogginess = (**gAppPrefs_h).howMultiFriendly;
  5286.     CalcCpuReleaseTicks(false);
  5287.     main_init();        /* for text editor */
  5288.  
  5289.     /* switch to regular cursor after initialization is done */
  5290.     SetCursor(&qd.arrow);
  5291.  
  5292.     /* if under System 6, gotta do an initial empty document ourselves */
  5293.     if (!gHasSys70)
  5294.         DoFile_New();
  5295.  
  5296.     // give the user some control!
  5297.     EnableMenus();
  5298.  
  5299.     /* Display initial credit screens now */
  5300.     print_credits();
  5301.     PrintMacCredits();
  5302.  
  5303.     /* Main event loop, sort of. */
  5304.     while (!gQuit)
  5305.     {
  5306.         Cooperate(true);
  5307.  
  5308.         if (gBeginRendering)
  5309.             DoRendering();
  5310.  
  5311.     } // while
  5312.     
  5313.     /* Clean up & exit. */
  5314.     exit_handler();
  5315.  
  5316.     return 0; // reduce MPW compiler warnings
  5317.  
  5318. } // main
  5319.  
  5320. // oops, too far...
  5321.